1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package javax.swing.plaf.basic;
27
28 import javax.swing.*;
29 import javax.swing.event.*;
30 import java.awt.*;
31 import java.awt.event.*;
32 import java.awt.datatransfer.*;
33 import java.beans.*;
34 import java.util.Enumeration;
35 import java.util.Hashtable;
36 import java.util.ArrayList;
37 import java.util.Collections;
38 import java.util.Comparator;
39 import javax.swing.plaf.ComponentUI;
40 import javax.swing.plaf.UIResource;
41 import javax.swing.plaf.TreeUI;
42 import javax.swing.tree.*;
43 import javax.swing.text.Position;
44 import javax.swing.plaf.basic.DragRecognitionSupport.BeforeDrag;
45 import sun.swing.SwingUtilities2;
46
47 import sun.swing.DefaultLookup;
48 import sun.swing.UIAction;
49
50
51
52
53
54
55
56
57
58 public class BasicTreeUI extends TreeUI
59 {
60 private static final StringBuilder BASELINE_COMPONENT_KEY =
61 new StringBuilder("Tree.baselineComponent");
62
63
64 static private final Actions SHARED_ACTION = new Actions();
65
66 transient protected Icon collapsedIcon;
67 transient protected Icon expandedIcon;
68
69
70
71
72
73 private Color hashColor;
74
75
76
77 protected int leftChildIndent;
78
79
80 protected int rightChildIndent;
81
82
83 protected int totalChildIndent;
84
85
86 protected Dimension preferredMinSize;
87
88
89 protected int lastSelectedRow;
90
91
92 protected JTree tree;
93
94
95 transient protected TreeCellRenderer currentCellRenderer;
96
97
98
99 protected boolean createdRenderer;
100
101
102 transient protected TreeCellEditor cellEditor;
103
104
105
106 protected boolean createdCellEditor;
107
108
109
110 protected boolean stopEditingInCompleteEditing;
111
112
113 protected CellRendererPane rendererPane;
114
115
116 protected Dimension preferredSize;
117
118
119 protected boolean validCachedPreferredSize;
120
121
122
123
124
125 protected AbstractLayoutCache treeState;
126
127
128
129 protected Hashtable<TreePath,Boolean> drawingCache;
130
131
132
133
134 protected boolean largeModel;
135
136
137 protected AbstractLayoutCache.NodeDimensions nodeDimensions;
138
139
140 protected TreeModel treeModel;
141
142
143 protected TreeSelectionModel treeSelectionModel;
144
145
146
147
148 protected int depthOffset;
149
150
151
152
153
154 protected Component editingComponent;
155
156
157 protected TreePath editingPath;
158
159
160
161 protected int editingRow;
162
163
164 protected boolean editorHasDifferentSize;
165
166
167 private int leadRow;
168
169
170 private boolean ignoreLAChange;
171
172
173 private boolean leftToRight;
174
175
176 private PropertyChangeListener propertyChangeListener;
177 private PropertyChangeListener selectionModelPropertyChangeListener;
178 private MouseListener mouseListener;
179 private FocusListener focusListener;
180 private KeyListener keyListener;
181
182
183 private ComponentListener componentListener;
184
185 private CellEditorListener cellEditorListener;
186
187 private TreeSelectionListener treeSelectionListener;
188
189 private TreeModelListener treeModelListener;
190
191 private TreeExpansionListener treeExpansionListener;
192
193
194 private boolean paintLines = true;
195
196
197 private boolean lineTypeDashed;
198
199
200
201
202
203 private long timeFactor = 1000L;
204
205 private Handler handler;
206
207
208
209
210
211 private MouseEvent releaseEvent;
212
213 public static ComponentUI createUI(JComponent x) {
214 return new BasicTreeUI();
215 }
216
217
218 static void loadActionMap(LazyActionMap map) {
219 map.put(new Actions(Actions.SELECT_PREVIOUS));
220 map.put(new Actions(Actions.SELECT_PREVIOUS_CHANGE_LEAD));
221 map.put(new Actions(Actions.SELECT_PREVIOUS_EXTEND_SELECTION));
222
223 map.put(new Actions(Actions.SELECT_NEXT));
224 map.put(new Actions(Actions.SELECT_NEXT_CHANGE_LEAD));
225 map.put(new Actions(Actions.SELECT_NEXT_EXTEND_SELECTION));
226
227 map.put(new Actions(Actions.SELECT_CHILD));
228 map.put(new Actions(Actions.SELECT_CHILD_CHANGE_LEAD));
229
230 map.put(new Actions(Actions.SELECT_PARENT));
231 map.put(new Actions(Actions.SELECT_PARENT_CHANGE_LEAD));
232
233 map.put(new Actions(Actions.SCROLL_UP_CHANGE_SELECTION));
234 map.put(new Actions(Actions.SCROLL_UP_CHANGE_LEAD));
235 map.put(new Actions(Actions.SCROLL_UP_EXTEND_SELECTION));
236
237 map.put(new Actions(Actions.SCROLL_DOWN_CHANGE_SELECTION));
238 map.put(new Actions(Actions.SCROLL_DOWN_EXTEND_SELECTION));
239 map.put(new Actions(Actions.SCROLL_DOWN_CHANGE_LEAD));
240
241 map.put(new Actions(Actions.SELECT_FIRST));
242 map.put(new Actions(Actions.SELECT_FIRST_CHANGE_LEAD));
243 map.put(new Actions(Actions.SELECT_FIRST_EXTEND_SELECTION));
244
245 map.put(new Actions(Actions.SELECT_LAST));
246 map.put(new Actions(Actions.SELECT_LAST_CHANGE_LEAD));
247 map.put(new Actions(Actions.SELECT_LAST_EXTEND_SELECTION));
248
249 map.put(new Actions(Actions.TOGGLE));
250
251 map.put(new Actions(Actions.CANCEL_EDITING));
252
253 map.put(new Actions(Actions.START_EDITING));
254
255 map.put(new Actions(Actions.SELECT_ALL));
256
257 map.put(new Actions(Actions.CLEAR_SELECTION));
258
259 map.put(new Actions(Actions.SCROLL_LEFT));
260 map.put(new Actions(Actions.SCROLL_RIGHT));
261
262 map.put(new Actions(Actions.SCROLL_LEFT_EXTEND_SELECTION));
263 map.put(new Actions(Actions.SCROLL_RIGHT_EXTEND_SELECTION));
264
265 map.put(new Actions(Actions.SCROLL_RIGHT_CHANGE_LEAD));
266 map.put(new Actions(Actions.SCROLL_LEFT_CHANGE_LEAD));
267
268 map.put(new Actions(Actions.EXPAND));
269 map.put(new Actions(Actions.COLLAPSE));
270 map.put(new Actions(Actions.MOVE_SELECTION_TO_PARENT));
271
272 map.put(new Actions(Actions.ADD_TO_SELECTION));
273 map.put(new Actions(Actions.TOGGLE_AND_ANCHOR));
274 map.put(new Actions(Actions.EXTEND_TO));
275 map.put(new Actions(Actions.MOVE_SELECTION_TO));
276
277 map.put(TransferHandler.getCutAction());
278 map.put(TransferHandler.getCopyAction());
279 map.put(TransferHandler.getPasteAction());
280 }
281
282
283 public BasicTreeUI() {
284 super();
285 }
286
287 protected Color getHashColor() {
288 return hashColor;
289 }
290
291 protected void setHashColor(Color color) {
292 hashColor = color;
293 }
294
295 public void setLeftChildIndent(int newAmount) {
296 leftChildIndent = newAmount;
297 totalChildIndent = leftChildIndent + rightChildIndent;
298 if(treeState != null)
299 treeState.invalidateSizes();
300 updateSize();
301 }
302
303 public int getLeftChildIndent() {
304 return leftChildIndent;
305 }
306
307 public void setRightChildIndent(int newAmount) {
308 rightChildIndent = newAmount;
309 totalChildIndent = leftChildIndent + rightChildIndent;
310 if(treeState != null)
311 treeState.invalidateSizes();
312 updateSize();
313 }
314
315 public int getRightChildIndent() {
316 return rightChildIndent;
317 }
318
319 public void setExpandedIcon(Icon newG) {
320 expandedIcon = newG;
321 }
322
323 public Icon getExpandedIcon() {
324 return expandedIcon;
325 }
326
327 public void setCollapsedIcon(Icon newG) {
328 collapsedIcon = newG;
329 }
330
331 public Icon getCollapsedIcon() {
332 return collapsedIcon;
333 }
334
335
336
337
338
339
340
341
342
343
344 protected void setLargeModel(boolean largeModel) {
345 if(getRowHeight() < 1)
346 largeModel = false;
347 if(this.largeModel != largeModel) {
348 completeEditing();
349 this.largeModel = largeModel;
350 treeState = createLayoutCache();
351 configureLayoutCache();
352 updateLayoutCacheExpandedNodesIfNecessary();
353 updateSize();
354 }
355 }
356
357 protected boolean isLargeModel() {
358 return largeModel;
359 }
360
361
362
363
364 protected void setRowHeight(int rowHeight) {
365 completeEditing();
366 if(treeState != null) {
367 setLargeModel(tree.isLargeModel());
368 treeState.setRowHeight(rowHeight);
369 updateSize();
370 }
371 }
372
373 protected int getRowHeight() {
374 return (tree == null) ? -1 : tree.getRowHeight();
375 }
376
377
378
379
380
381 protected void setCellRenderer(TreeCellRenderer tcr) {
382 completeEditing();
383 updateRenderer();
384 if(treeState != null) {
385 treeState.invalidateSizes();
386 updateSize();
387 }
388 }
389
390
391
392
393
394 protected TreeCellRenderer getCellRenderer() {
395 return currentCellRenderer;
396 }
397
398
399
400
401 protected void setModel(TreeModel model) {
402 completeEditing();
403 if(treeModel != null && treeModelListener != null)
404 treeModel.removeTreeModelListener(treeModelListener);
405 treeModel = model;
406 if(treeModel != null) {
407 if(treeModelListener != null)
408 treeModel.addTreeModelListener(treeModelListener);
409 }
410 if(treeState != null) {
411 treeState.setModel(model);
412 updateLayoutCacheExpandedNodesIfNecessary();
413 updateSize();
414 }
415 }
416
417 protected TreeModel getModel() {
418 return treeModel;
419 }
420
421
422
423
424 protected void setRootVisible(boolean newValue) {
425 completeEditing();
426 updateDepthOffset();
427 if(treeState != null) {
428 treeState.setRootVisible(newValue);
429 treeState.invalidateSizes();
430 updateSize();
431 }
432 }
433
434 protected boolean isRootVisible() {
435 return (tree != null) ? tree.isRootVisible() : false;
436 }
437
438
439
440
441 protected void setShowsRootHandles(boolean newValue) {
442 completeEditing();
443 updateDepthOffset();
444 if(treeState != null) {
445 treeState.invalidateSizes();
446 updateSize();
447 }
448 }
449
450 protected boolean getShowsRootHandles() {
451 return (tree != null) ? tree.getShowsRootHandles() : false;
452 }
453
454
455
456
457 protected void setCellEditor(TreeCellEditor editor) {
458 updateCellEditor();
459 }
460
461 protected TreeCellEditor getCellEditor() {
462 return (tree != null) ? tree.getCellEditor() : null;
463 }
464
465
466
467
468 protected void setEditable(boolean newValue) {
469 updateCellEditor();
470 }
471
472 protected boolean isEditable() {
473 return (tree != null) ? tree.isEditable() : false;
474 }
475
476
477
478
479
480 protected void setSelectionModel(TreeSelectionModel newLSM) {
481 completeEditing();
482 if(selectionModelPropertyChangeListener != null &&
483 treeSelectionModel != null)
484 treeSelectionModel.removePropertyChangeListener
485 (selectionModelPropertyChangeListener);
486 if(treeSelectionListener != null && treeSelectionModel != null)
487 treeSelectionModel.removeTreeSelectionListener
488 (treeSelectionListener);
489 treeSelectionModel = newLSM;
490 if(treeSelectionModel != null) {
491 if(selectionModelPropertyChangeListener != null)
492 treeSelectionModel.addPropertyChangeListener
493 (selectionModelPropertyChangeListener);
494 if(treeSelectionListener != null)
495 treeSelectionModel.addTreeSelectionListener
496 (treeSelectionListener);
497 if(treeState != null)
498 treeState.setSelectionModel(treeSelectionModel);
499 }
500 else if(treeState != null)
501 treeState.setSelectionModel(null);
502 if(tree != null)
503 tree.repaint();
504 }
505
506 protected TreeSelectionModel getSelectionModel() {
507 return treeSelectionModel;
508 }
509
510
511
512
513
514
515
516
517
518
519 public Rectangle getPathBounds(JTree tree, TreePath path) {
520 if(tree != null && treeState != null) {
521 return getPathBounds(path, tree.getInsets(), new Rectangle());
522 }
523 return null;
524 }
525
526 private Rectangle getPathBounds(TreePath path, Insets insets,
527 Rectangle bounds) {
528 bounds = treeState.getBounds(path, bounds);
529 if (bounds != null) {
530 if (leftToRight) {
531 bounds.x += insets.left;
532 } else {
533 bounds.x = tree.getWidth() - (bounds.x + bounds.width) -
534 insets.right;
535 }
536 bounds.y += insets.top;
537 }
538 return bounds;
539 }
540
541
542
543
544
545 public TreePath getPathForRow(JTree tree, int row) {
546 return (treeState != null) ? treeState.getPathForRow(row) : null;
547 }
548
549
550
551
552
553
554 public int getRowForPath(JTree tree, TreePath path) {
555 return (treeState != null) ? treeState.getRowForPath(path) : -1;
556 }
557
558
559
560
561 public int getRowCount(JTree tree) {
562 return (treeState != null) ? treeState.getRowCount() : 0;
563 }
564
565
566
567
568
569
570
571
572 public TreePath getClosestPathForLocation(JTree tree, int x, int y) {
573 if(tree != null && treeState != null) {
574
575
576 y -= tree.getInsets().top;
577 return treeState.getPathClosestTo(x, y);
578 }
579 return null;
580 }
581
582
583
584
585
586 public boolean isEditing(JTree tree) {
587 return (editingComponent != null);
588 }
589
590
591
592
593
594
595 public boolean stopEditing(JTree tree) {
596 if(editingComponent != null && cellEditor.stopCellEditing()) {
597 completeEditing(false, false, true);
598 return true;
599 }
600 return false;
601 }
602
603
604
605
606 public void cancelEditing(JTree tree) {
607 if(editingComponent != null) {
608 completeEditing(false, true, false);
609 }
610 }
611
612
613
614
615
616 public void startEditingAtPath(JTree tree, TreePath path) {
617 tree.scrollPathToVisible(path);
618 if(path != null && tree.isVisible(path))
619 startEditing(path, null);
620 }
621
622
623
624
625 public TreePath getEditingPath(JTree tree) {
626 return editingPath;
627 }
628
629
630
631
632
633 public void installUI(JComponent c) {
634 if ( c == null ) {
635 throw new NullPointerException( "null component passed to BasicTreeUI.installUI()" );
636 }
637
638 tree = (JTree)c;
639
640 prepareForUIInstall();
641
642
643 installDefaults();
644 installKeyboardActions();
645 installComponents();
646 installListeners();
647
648 completeUIInstall();
649 }
650
651
652
653
654
655 protected void prepareForUIInstall() {
656 drawingCache = new Hashtable<TreePath,Boolean>(7);
657
658
659 leftToRight = BasicGraphicsUtils.isLeftToRight(tree);
660 stopEditingInCompleteEditing = true;
661 lastSelectedRow = -1;
662 leadRow = -1;
663 preferredSize = new Dimension();
664
665 largeModel = tree.isLargeModel();
666 if(getRowHeight() <= 0)
667 largeModel = false;
668 setModel(tree.getModel());
669 }
670
671
672
673
674
675 protected void completeUIInstall() {
676
677
678 this.setShowsRootHandles(tree.getShowsRootHandles());
679
680 updateRenderer();
681
682 updateDepthOffset();
683
684 setSelectionModel(tree.getSelectionModel());
685
686
687 treeState = createLayoutCache();
688 configureLayoutCache();
689
690 updateSize();
691 }
692
693 protected void installDefaults() {
694 if(tree.getBackground() == null ||
695 tree.getBackground() instanceof UIResource) {
696 tree.setBackground(UIManager.getColor("Tree.background"));
697 }
698 if(getHashColor() == null || getHashColor() instanceof UIResource) {
699 setHashColor(UIManager.getColor("Tree.hash"));
700 }
701 if (tree.getFont() == null || tree.getFont() instanceof UIResource)
702 tree.setFont( UIManager.getFont("Tree.font") );
703
704
705
706
707
708
709
710
711 setExpandedIcon( (Icon)UIManager.get( "Tree.expandedIcon" ) );
712 setCollapsedIcon( (Icon)UIManager.get( "Tree.collapsedIcon" ) );
713
714 setLeftChildIndent(((Integer)UIManager.get("Tree.leftChildIndent")).
715 intValue());
716 setRightChildIndent(((Integer)UIManager.get("Tree.rightChildIndent")).
717 intValue());
718
719 LookAndFeel.installProperty(tree, "rowHeight",
720 UIManager.get("Tree.rowHeight"));
721
722 largeModel = (tree.isLargeModel() && tree.getRowHeight() > 0);
723
724 Object scrollsOnExpand = UIManager.get("Tree.scrollsOnExpand");
725 if (scrollsOnExpand != null) {
726 LookAndFeel.installProperty(tree, "scrollsOnExpand", scrollsOnExpand);
727 }
728
729 paintLines = UIManager.getBoolean("Tree.paintLines");
730 lineTypeDashed = UIManager.getBoolean("Tree.lineTypeDashed");
731
732 Long l = (Long)UIManager.get("Tree.timeFactor");
733 timeFactor = (l!=null) ? l.longValue() : 1000L;
734
735 Object showsRootHandles = UIManager.get("Tree.showsRootHandles");
736 if (showsRootHandles != null) {
737 LookAndFeel.installProperty(tree,
738 JTree.SHOWS_ROOT_HANDLES_PROPERTY, showsRootHandles);
739 }
740 }
741
742 protected void installListeners() {
743 if ( (propertyChangeListener = createPropertyChangeListener())
744 != null ) {
745 tree.addPropertyChangeListener(propertyChangeListener);
746 }
747 if ( (mouseListener = createMouseListener()) != null ) {
748 tree.addMouseListener(mouseListener);
749 if (mouseListener instanceof MouseMotionListener) {
750 tree.addMouseMotionListener((MouseMotionListener)mouseListener);
751 }
752 }
753 if ((focusListener = createFocusListener()) != null ) {
754 tree.addFocusListener(focusListener);
755 }
756 if ((keyListener = createKeyListener()) != null) {
757 tree.addKeyListener(keyListener);
758 }
759 if((treeExpansionListener = createTreeExpansionListener()) != null) {
760 tree.addTreeExpansionListener(treeExpansionListener);
761 }
762 if((treeModelListener = createTreeModelListener()) != null &&
763 treeModel != null) {
764 treeModel.addTreeModelListener(treeModelListener);
765 }
766 if((selectionModelPropertyChangeListener =
767 createSelectionModelPropertyChangeListener()) != null &&
768 treeSelectionModel != null) {
769 treeSelectionModel.addPropertyChangeListener
770 (selectionModelPropertyChangeListener);
771 }
772 if((treeSelectionListener = createTreeSelectionListener()) != null &&
773 treeSelectionModel != null) {
774 treeSelectionModel.addTreeSelectionListener(treeSelectionListener);
775 }
776
777 TransferHandler th = tree.getTransferHandler();
778 if (th == null || th instanceof UIResource) {
779 tree.setTransferHandler(defaultTransferHandler);
780
781
782 if (tree.getDropTarget() instanceof UIResource) {
783 tree.setDropTarget(null);
784 }
785 }
786
787 LookAndFeel.installProperty(tree, "opaque", Boolean.TRUE);
788 }
789
790 protected void installKeyboardActions() {
791 InputMap km = getInputMap(JComponent.
792 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
793
794 SwingUtilities.replaceUIInputMap(tree, JComponent.
795 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
796 km);
797 km = getInputMap(JComponent.WHEN_FOCUSED);
798 SwingUtilities.replaceUIInputMap(tree, JComponent.WHEN_FOCUSED, km);
799
800 LazyActionMap.installLazyActionMap(tree, BasicTreeUI.class,
801 "Tree.actionMap");
802 }
803
804 InputMap getInputMap(int condition) {
805 if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
806 return (InputMap)DefaultLookup.get(tree, this,
807 "Tree.ancestorInputMap");
808 }
809 else if (condition == JComponent.WHEN_FOCUSED) {
810 InputMap keyMap = (InputMap)DefaultLookup.get(tree, this,
811 "Tree.focusInputMap");
812 InputMap rtlKeyMap;
813
814 if (tree.getComponentOrientation().isLeftToRight() ||
815 ((rtlKeyMap = (InputMap)DefaultLookup.get(tree, this,
816 "Tree.focusInputMap.RightToLeft")) == null)) {
817 return keyMap;
818 } else {
819 rtlKeyMap.setParent(keyMap);
820 return rtlKeyMap;
821 }
822 }
823 return null;
824 }
825
826
827
828
829 protected void installComponents() {
830 if ((rendererPane = createCellRendererPane()) != null) {
831 tree.add( rendererPane );
832 }
833 }
834
835
836
837
838
839
840
841
842
843 protected AbstractLayoutCache.NodeDimensions createNodeDimensions() {
844 return new NodeDimensionsHandler();
845 }
846
847
848
849
850
851 protected PropertyChangeListener createPropertyChangeListener() {
852 return getHandler();
853 }
854
855 private Handler getHandler() {
856 if (handler == null) {
857 handler = new Handler();
858 }
859 return handler;
860 }
861
862
863
864
865
866 protected MouseListener createMouseListener() {
867 return getHandler();
868 }
869
870
871
872
873
874 protected FocusListener createFocusListener() {
875 return getHandler();
876 }
877
878
879
880
881
882 protected KeyListener createKeyListener() {
883 return getHandler();
884 }
885
886
887
888
889
890 protected PropertyChangeListener createSelectionModelPropertyChangeListener() {
891 return getHandler();
892 }
893
894
895
896
897
898 protected TreeSelectionListener createTreeSelectionListener() {
899 return getHandler();
900 }
901
902
903
904
905 protected CellEditorListener createCellEditorListener() {
906 return getHandler();
907 }
908
909
910
911
912
913
914 protected ComponentListener createComponentListener() {
915 return new ComponentHandler();
916 }
917
918
919
920
921
922 protected TreeExpansionListener createTreeExpansionListener() {
923 return getHandler();
924 }
925
926
927
928
929
930 protected AbstractLayoutCache createLayoutCache() {
931 if(isLargeModel() && getRowHeight() > 0) {
932 return new FixedHeightLayoutCache();
933 }
934 return new VariableHeightLayoutCache();
935 }
936
937
938
939
940 protected CellRendererPane createCellRendererPane() {
941 return new CellRendererPane();
942 }
943
944
945
946
947 protected TreeCellEditor createDefaultCellEditor() {
948 if(currentCellRenderer != null &&
949 (currentCellRenderer instanceof DefaultTreeCellRenderer)) {
950 DefaultTreeCellEditor editor = new DefaultTreeCellEditor
951 (tree, (DefaultTreeCellRenderer)currentCellRenderer);
952
953 return editor;
954 }
955 return new DefaultTreeCellEditor(tree, null);
956 }
957
958
959
960
961
962 protected TreeCellRenderer createDefaultCellRenderer() {
963 return new DefaultTreeCellRenderer();
964 }
965
966
967
968
969 protected TreeModelListener createTreeModelListener() {
970 return getHandler();
971 }
972
973
974
975
976
977 public void uninstallUI(JComponent c) {
978 completeEditing();
979
980 prepareForUIUninstall();
981
982 uninstallDefaults();
983 uninstallListeners();
984 uninstallKeyboardActions();
985 uninstallComponents();
986
987 completeUIUninstall();
988 }
989
990 protected void prepareForUIUninstall() {
991 }
992
993 protected void completeUIUninstall() {
994 if(createdRenderer) {
995 tree.setCellRenderer(null);
996 }
997 if(createdCellEditor) {
998 tree.setCellEditor(null);
999 }
1000 cellEditor = null;
1001 currentCellRenderer = null;
1002 rendererPane = null;
1003 componentListener = null;
1004 propertyChangeListener = null;
1005 mouseListener = null;
1006 focusListener = null;
1007 keyListener = null;
1008 setSelectionModel(null);
1009 treeState = null;
1010 drawingCache = null;
1011 selectionModelPropertyChangeListener = null;
1012 tree = null;
1013 treeModel = null;
1014 treeSelectionModel = null;
1015 treeSelectionListener = null;
1016 treeExpansionListener = null;
1017 }
1018
1019 protected void uninstallDefaults() {
1020 if (tree.getTransferHandler() instanceof UIResource) {
1021 tree.setTransferHandler(null);
1022 }
1023 }
1024
1025 protected void uninstallListeners() {
1026 if(componentListener != null) {
1027 tree.removeComponentListener(componentListener);
1028 }
1029 if (propertyChangeListener != null) {
1030 tree.removePropertyChangeListener(propertyChangeListener);
1031 }
1032 if (mouseListener != null) {
1033 tree.removeMouseListener(mouseListener);
1034 if (mouseListener instanceof MouseMotionListener) {
1035 tree.removeMouseMotionListener((MouseMotionListener)mouseListener);
1036 }
1037 }
1038 if (focusListener != null) {
1039 tree.removeFocusListener(focusListener);
1040 }
1041 if (keyListener != null) {
1042 tree.removeKeyListener(keyListener);
1043 }
1044 if(treeExpansionListener != null) {
1045 tree.removeTreeExpansionListener(treeExpansionListener);
1046 }
1047 if(treeModel != null && treeModelListener != null) {
1048 treeModel.removeTreeModelListener(treeModelListener);
1049 }
1050 if(selectionModelPropertyChangeListener != null &&
1051 treeSelectionModel != null) {
1052 treeSelectionModel.removePropertyChangeListener
1053 (selectionModelPropertyChangeListener);
1054 }
1055 if(treeSelectionListener != null && treeSelectionModel != null) {
1056 treeSelectionModel.removeTreeSelectionListener
1057 (treeSelectionListener);
1058 }
1059 handler = null;
1060 }
1061
1062 protected void uninstallKeyboardActions() {
1063 SwingUtilities.replaceUIActionMap(tree, null);
1064 SwingUtilities.replaceUIInputMap(tree, JComponent.
1065 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
1066 null);
1067 SwingUtilities.replaceUIInputMap(tree, JComponent.WHEN_FOCUSED, null);
1068 }
1069
1070
1071
1072
1073 protected void uninstallComponents() {
1074 if(rendererPane != null) {
1075 tree.remove(rendererPane);
1076 }
1077 }
1078
1079
1080
1081
1082 private void redoTheLayout() {
1083 if (treeState != null) {
1084 treeState.invalidateSizes();
1085 }
1086 }
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096 public int getBaseline(JComponent c, int width, int height) {
1097 super.getBaseline(c, width, height);
1098 UIDefaults lafDefaults = UIManager.getLookAndFeelDefaults();
1099 Component renderer = (Component)lafDefaults.get(
1100 BASELINE_COMPONENT_KEY);
1101 if (renderer == null) {
1102 TreeCellRenderer tcr = createDefaultCellRenderer();
1103 renderer = tcr.getTreeCellRendererComponent(
1104 tree, "a", false, false, false, -1, false);
1105 lafDefaults.put(BASELINE_COMPONENT_KEY, renderer);
1106 }
1107 int rowHeight = tree.getRowHeight();
1108 int baseline;
1109 if (rowHeight > 0) {
1110 baseline = renderer.getBaseline(Integer.MAX_VALUE, rowHeight);
1111 }
1112 else {
1113 Dimension pref = renderer.getPreferredSize();
1114 baseline = renderer.getBaseline(pref.width, pref.height);
1115 }
1116 return baseline + tree.getInsets().top;
1117 }
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127 public Component.BaselineResizeBehavior getBaselineResizeBehavior(
1128 JComponent c) {
1129 super.getBaselineResizeBehavior(c);
1130 return Component.BaselineResizeBehavior.CONSTANT_ASCENT;
1131 }
1132
1133
1134
1135
1136
1137 public void paint(Graphics g, JComponent c) {
1138 if (tree != c) {
1139 throw new InternalError("incorrect component");
1140 }
1141
1142
1143 if(treeState == null) {
1144 return;
1145 }
1146
1147 Rectangle paintBounds = g.getClipBounds();
1148 Insets insets = tree.getInsets();
1149 TreePath initialPath = getClosestPathForLocation
1150 (tree, 0, paintBounds.y);
1151 Enumeration paintingEnumerator = treeState.getVisiblePathsFrom
1152 (initialPath);
1153 int row = treeState.getRowForPath(initialPath);
1154 int endY = paintBounds.y + paintBounds.height;
1155
1156 drawingCache.clear();
1157
1158 if(initialPath != null && paintingEnumerator != null) {
1159 TreePath parentPath = initialPath;
1160
1161
1162
1163
1164 parentPath = parentPath.getParentPath();
1165 while(parentPath != null) {
1166 paintVerticalPartOfLeg(g, paintBounds, insets, parentPath);
1167 drawingCache.put(parentPath, Boolean.TRUE);
1168 parentPath = parentPath.getParentPath();
1169 }
1170
1171 boolean done = false;
1172
1173 boolean isExpanded;
1174 boolean hasBeenExpanded;
1175 boolean isLeaf;
1176 Rectangle boundsBuffer = new Rectangle();
1177 Rectangle bounds;
1178 TreePath path;
1179 boolean rootVisible = isRootVisible();
1180
1181 while(!done && paintingEnumerator.hasMoreElements()) {
1182 path = (TreePath)paintingEnumerator.nextElement();
1183 if(path != null) {
1184 isLeaf = treeModel.isLeaf(path.getLastPathComponent());
1185 if(isLeaf)
1186 isExpanded = hasBeenExpanded = false;
1187 else {
1188 isExpanded = treeState.getExpandedState(path);
1189 hasBeenExpanded = tree.hasBeenExpanded(path);
1190 }
1191 bounds = getPathBounds(path, insets, boundsBuffer);
1192 if(bounds == null)
1193
1194
1195
1196
1197 return;
1198
1199 parentPath = path.getParentPath();
1200 if(parentPath != null) {
1201 if(drawingCache.get(parentPath) == null) {
1202 paintVerticalPartOfLeg(g, paintBounds,
1203 insets, parentPath);
1204 drawingCache.put(parentPath, Boolean.TRUE);
1205 }
1206 paintHorizontalPartOfLeg(g, paintBounds, insets,
1207 bounds, path, row,
1208 isExpanded,
1209 hasBeenExpanded, isLeaf);
1210 }
1211 else if(rootVisible && row == 0) {
1212 paintHorizontalPartOfLeg(g, paintBounds, insets,
1213 bounds, path, row,
1214 isExpanded,
1215 hasBeenExpanded, isLeaf);
1216 }
1217 if(shouldPaintExpandControl(path, row, isExpanded,
1218 hasBeenExpanded, isLeaf)) {
1219 paintExpandControl(g, paintBounds, insets, bounds,
1220 path, row, isExpanded,
1221 hasBeenExpanded, isLeaf);
1222 }
1223 paintRow(g, paintBounds, insets, bounds, path,
1224 row, isExpanded, hasBeenExpanded, isLeaf);
1225 if((bounds.y + bounds.height) >= endY)
1226 done = true;
1227 }
1228 else {
1229 done = true;
1230 }
1231 row++;
1232 }
1233 }
1234
1235 paintDropLine(g);
1236
1237
1238 rendererPane.removeAll();
1239
1240 drawingCache.clear();
1241 }
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252 protected boolean isDropLine(JTree.DropLocation loc) {
1253 return loc != null && loc.getPath() != null && loc.getChildIndex() != -1;
1254 }
1255
1256
1257
1258
1259
1260
1261
1262 protected void paintDropLine(Graphics g) {
1263 JTree.DropLocation loc = tree.getDropLocation();
1264 if (!isDropLine(loc)) {
1265 return;
1266 }
1267
1268 Color c = UIManager.getColor("Tree.dropLineColor");
1269 if (c != null) {
1270 g.setColor(c);
1271 Rectangle rect = getDropLineRect(loc);
1272 g.fillRect(rect.x, rect.y, rect.width, rect.height);
1273 }
1274 }
1275
1276
1277
1278
1279
1280
1281
1282
1283 protected Rectangle getDropLineRect(JTree.DropLocation loc) {
1284 Rectangle rect;
1285 TreePath path = loc.getPath();
1286 int index = loc.getChildIndex();
1287 boolean ltr = leftToRight;
1288
1289 Insets insets = tree.getInsets();
1290
1291 if (tree.getRowCount() == 0) {
1292 rect = new Rectangle(insets.left,
1293 insets.top,
1294 tree.getWidth() - insets.left - insets.right,
1295 0);
1296 } else {
1297 TreeModel model = getModel();
1298 Object root = model.getRoot();
1299
1300 if (path.getLastPathComponent() == root
1301 && index >= model.getChildCount(root)) {
1302
1303 rect = tree.getRowBounds(tree.getRowCount() - 1);
1304 rect.y = rect.y + rect.height;
1305 Rectangle xRect;
1306
1307 if (!tree.isRootVisible()) {
1308 xRect = tree.getRowBounds(0);
1309 } else if (model.getChildCount(root) == 0){
1310 xRect = tree.getRowBounds(0);
1311 xRect.x += totalChildIndent;
1312 xRect.width -= totalChildIndent + totalChildIndent;
1313 } else {
1314 TreePath lastChildPath = path.pathByAddingChild(
1315 model.getChild(root, model.getChildCount(root) - 1));
1316 xRect = tree.getPathBounds(lastChildPath);
1317 }
1318
1319 rect.x = xRect.x;
1320 rect.width = xRect.width;
1321 } else {
1322 rect = tree.getPathBounds(path.pathByAddingChild(
1323 model.getChild(path.getLastPathComponent(), index)));
1324 }
1325 }
1326
1327 if (rect.y != 0) {
1328 rect.y--;
1329 }
1330
1331 if (!ltr) {
1332 rect.x = rect.x + rect.width - 100;
1333 }
1334
1335 rect.width = 100;
1336 rect.height = 2;
1337
1338 return rect;
1339 }
1340
1341
1342
1343
1344
1345
1346 protected void paintHorizontalPartOfLeg(Graphics g, Rectangle clipBounds,
1347 Insets insets, Rectangle bounds,
1348 TreePath path, int row,
1349 boolean isExpanded,
1350 boolean hasBeenExpanded, boolean
1351 isLeaf) {
1352 if (!paintLines) {
1353 return;
1354 }
1355
1356
1357 int depth = path.getPathCount() - 1;
1358 if((depth == 0 || (depth == 1 && !isRootVisible())) &&
1359 !getShowsRootHandles()) {
1360 return;
1361 }
1362
1363 int clipLeft = clipBounds.x;
1364 int clipRight = clipBounds.x + clipBounds.width;
1365 int clipTop = clipBounds.y;
1366 int clipBottom = clipBounds.y + clipBounds.height;
1367 int lineY = bounds.y + bounds.height / 2;
1368
1369 if (leftToRight) {
1370 int leftX = bounds.x - getRightChildIndent();
1371 int nodeX = bounds.x - getHorizontalLegBuffer();
1372
1373 if(lineY >= clipTop
1374 && lineY < clipBottom
1375 && nodeX >= clipLeft
1376 && leftX < clipRight
1377 && leftX < nodeX) {
1378
1379 g.setColor(getHashColor());
1380 paintHorizontalLine(g, tree, lineY, leftX, nodeX - 1);
1381 }
1382 } else {
1383 int nodeX = bounds.x + bounds.width + getHorizontalLegBuffer();
1384 int rightX = bounds.x + bounds.width + getRightChildIndent();
1385
1386 if(lineY >= clipTop
1387 && lineY < clipBottom
1388 && rightX >= clipLeft
1389 && nodeX < clipRight
1390 && nodeX < rightX) {
1391
1392 g.setColor(getHashColor());
1393 paintHorizontalLine(g, tree, lineY, nodeX, rightX - 1);
1394 }
1395 }
1396 }
1397
1398
1399
1400
1401
1402 protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds,
1403 Insets insets, TreePath path) {
1404 if (!paintLines) {
1405 return;
1406 }
1407
1408 int depth = path.getPathCount() - 1;
1409 if (depth == 0 && !getShowsRootHandles() && !isRootVisible()) {
1410 return;
1411 }
1412 int lineX = getRowX(-1, depth + 1);
1413 if (leftToRight) {
1414 lineX = lineX - getRightChildIndent() + insets.left;
1415 }
1416 else {
1417 lineX = tree.getWidth() - lineX - insets.right +
1418 getRightChildIndent() - 1;
1419 }
1420 int clipLeft = clipBounds.x;
1421 int clipRight = clipBounds.x + (clipBounds.width - 1);
1422
1423 if (lineX >= clipLeft && lineX <= clipRight) {
1424 int clipTop = clipBounds.y;
1425 int clipBottom = clipBounds.y + clipBounds.height;
1426 Rectangle parentBounds = getPathBounds(tree, path);
1427 Rectangle lastChildBounds = getPathBounds(tree,
1428 getLastChildPath(path));
1429
1430 if(lastChildBounds == null)
1431
1432
1433
1434
1435 return;
1436
1437 int top;
1438
1439 if(parentBounds == null) {
1440 top = Math.max(insets.top + getVerticalLegBuffer(),
1441 clipTop);
1442 }
1443 else
1444 top = Math.max(parentBounds.y + parentBounds.height +
1445 getVerticalLegBuffer(), clipTop);
1446 if(depth == 0 && !isRootVisible()) {
1447 TreeModel model = getModel();
1448
1449 if(model != null) {
1450 Object root = model.getRoot();
1451
1452 if(model.getChildCount(root) > 0) {
1453 parentBounds = getPathBounds(tree, path.
1454 pathByAddingChild(model.getChild(root, 0)));
1455 if(parentBounds != null)
1456 top = Math.max(insets.top + getVerticalLegBuffer(),
1457 parentBounds.y +
1458 parentBounds.height / 2);
1459 }
1460 }
1461 }
1462
1463 int bottom = Math.min(lastChildBounds.y +
1464 (lastChildBounds.height / 2), clipBottom);
1465
1466 if (top <= bottom) {
1467 g.setColor(getHashColor());
1468 paintVerticalLine(g, tree, lineX, top, bottom);
1469 }
1470 }
1471 }
1472
1473
1474
1475
1476
1477 protected void paintExpandControl(Graphics g,
1478 Rectangle clipBounds, Insets insets,
1479 Rectangle bounds, TreePath path,
1480 int row, boolean isExpanded,
1481 boolean hasBeenExpanded,
1482 boolean isLeaf) {
1483 Object value = path.getLastPathComponent();
1484
1485
1486
1487 if (!isLeaf && (!hasBeenExpanded ||
1488 treeModel.getChildCount(value) > 0)) {
1489 int middleXOfKnob;
1490 if (leftToRight) {
1491 middleXOfKnob = bounds.x - getRightChildIndent() + 1;
1492 } else {
1493 middleXOfKnob = bounds.x + bounds.width + getRightChildIndent() - 1;
1494 }
1495 int middleYOfKnob = bounds.y + (bounds.height / 2);
1496
1497 if (isExpanded) {
1498 Icon expandedIcon = getExpandedIcon();
1499 if(expandedIcon != null)
1500 drawCentered(tree, g, expandedIcon, middleXOfKnob,
1501 middleYOfKnob );
1502 }
1503 else {
1504 Icon collapsedIcon = getCollapsedIcon();
1505 if(collapsedIcon != null)
1506 drawCentered(tree, g, collapsedIcon, middleXOfKnob,
1507 middleYOfKnob);
1508 }
1509 }
1510 }
1511
1512
1513
1514
1515
1516 protected void paintRow(Graphics g, Rectangle clipBounds,
1517 Insets insets, Rectangle bounds, TreePath path,
1518 int row, boolean isExpanded,
1519 boolean hasBeenExpanded, boolean isLeaf) {
1520
1521 if(editingComponent != null && editingRow == row)
1522 return;
1523
1524 int leadIndex;
1525
1526 if(tree.hasFocus()) {
1527 leadIndex = getLeadSelectionRow();
1528 }
1529 else
1530 leadIndex = -1;
1531
1532 Component component;
1533
1534 component = currentCellRenderer.getTreeCellRendererComponent
1535 (tree, path.getLastPathComponent(),
1536 tree.isRowSelected(row), isExpanded, isLeaf, row,
1537 (leadIndex == row));
1538
1539 rendererPane.paintComponent(g, component, tree, bounds.x, bounds.y,
1540 bounds.width, bounds.height, true);
1541 }
1542
1543
1544
1545
1546
1547 protected boolean shouldPaintExpandControl(TreePath path, int row,
1548 boolean isExpanded,
1549 boolean hasBeenExpanded,
1550 boolean isLeaf) {
1551 if(isLeaf)
1552 return false;
1553
1554 int depth = path.getPathCount() - 1;
1555
1556 if((depth == 0 || (depth == 1 && !isRootVisible())) &&
1557 !getShowsRootHandles())
1558 return false;
1559 return true;
1560 }
1561
1562
1563
1564
1565 protected void paintVerticalLine(Graphics g, JComponent c, int x, int top,
1566 int bottom) {
1567 if (lineTypeDashed) {
1568 drawDashedVerticalLine(g, x, top, bottom);
1569 } else {
1570 g.drawLine(x, top, x, bottom);
1571 }
1572 }
1573
1574
1575
1576
1577 protected void paintHorizontalLine(Graphics g, JComponent c, int y,
1578 int left, int right) {
1579 if (lineTypeDashed) {
1580 drawDashedHorizontalLine(g, y, left, right);
1581 } else {
1582 g.drawLine(left, y, right, y);
1583 }
1584 }
1585
1586
1587
1588
1589
1590 protected int getVerticalLegBuffer() {
1591 return 0;
1592 }
1593
1594
1595
1596
1597
1598
1599 protected int getHorizontalLegBuffer() {
1600 return 0;
1601 }
1602
1603 private int findCenteredX(int x, int iconWidth) {
1604 return leftToRight
1605 ? x - (int)Math.ceil(iconWidth / 2.0)
1606 : x - (int)Math.floor(iconWidth / 2.0);
1607 }
1608
1609
1610
1611
1612
1613
1614 protected void drawCentered(Component c, Graphics graphics, Icon icon,
1615 int x, int y) {
1616 icon.paintIcon(c, graphics,
1617 findCenteredX(x, icon.getIconWidth()),
1618 y - icon.getIconHeight() / 2);
1619 }
1620
1621
1622
1623 protected void drawDashedHorizontalLine(Graphics g, int y, int x1, int x2){
1624
1625
1626
1627 x1 += (x1 % 2);
1628
1629 for (int x = x1; x <= x2; x+=2) {
1630 g.drawLine(x, y, x, y);
1631 }
1632 }
1633
1634
1635
1636 protected void drawDashedVerticalLine(Graphics g, int x, int y1, int y2) {
1637
1638
1639
1640 y1 += (y1 % 2);
1641
1642 for (int y = y1; y <= y2; y+=2) {
1643 g.drawLine(x, y, x, y);
1644 }
1645 }
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663 protected int getRowX(int row, int depth) {
1664 return totalChildIndent * (depth + depthOffset);
1665 }
1666
1667
1668
1669
1670
1671 protected void updateLayoutCacheExpandedNodes() {
1672 if(treeModel != null && treeModel.getRoot() != null)
1673 updateExpandedDescendants(new TreePath(treeModel.getRoot()));
1674 }
1675
1676 private void updateLayoutCacheExpandedNodesIfNecessary() {
1677 if (treeModel != null && treeModel.getRoot() != null) {
1678 TreePath rootPath = new TreePath(treeModel.getRoot());
1679 if (tree.isExpanded(rootPath)) {
1680 updateLayoutCacheExpandedNodes();
1681 } else {
1682 treeState.setExpandedState(rootPath, false);
1683 }
1684 }
1685 }
1686
1687
1688
1689
1690
1691
1692 protected void updateExpandedDescendants(TreePath path) {
1693 completeEditing();
1694 if(treeState != null) {
1695 treeState.setExpandedState(path, true);
1696
1697 Enumeration descendants = tree.getExpandedDescendants(path);
1698
1699 if(descendants != null) {
1700 while(descendants.hasMoreElements()) {
1701 path = (TreePath)descendants.nextElement();
1702 treeState.setExpandedState(path, true);
1703 }
1704 }
1705 updateLeadSelectionRow();
1706 updateSize();
1707 }
1708 }
1709
1710
1711
1712
1713 protected TreePath getLastChildPath(TreePath parent) {
1714 if(treeModel != null) {
1715 int childCount = treeModel.getChildCount
1716 (parent.getLastPathComponent());
1717
1718 if(childCount > 0)
1719 return parent.pathByAddingChild(treeModel.getChild
1720 (parent.getLastPathComponent(), childCount - 1));
1721 }
1722 return null;
1723 }
1724
1725
1726
1727
1728 protected void updateDepthOffset() {
1729 if(isRootVisible()) {
1730 if(getShowsRootHandles())
1731 depthOffset = 1;
1732 else
1733 depthOffset = 0;
1734 }
1735 else if(!getShowsRootHandles())
1736 depthOffset = -1;
1737 else
1738 depthOffset = 0;
1739 }
1740
1741
1742
1743
1744
1745
1746 protected void updateCellEditor() {
1747 TreeCellEditor newEditor;
1748
1749 completeEditing();
1750 if(tree == null)
1751 newEditor = null;
1752 else {
1753 if(tree.isEditable()) {
1754 newEditor = tree.getCellEditor();
1755 if(newEditor == null) {
1756 newEditor = createDefaultCellEditor();
1757 if(newEditor != null) {
1758 tree.setCellEditor(newEditor);
1759 createdCellEditor = true;
1760 }
1761 }
1762 }
1763 else
1764 newEditor = null;
1765 }
1766 if(newEditor != cellEditor) {
1767 if(cellEditor != null && cellEditorListener != null)
1768 cellEditor.removeCellEditorListener(cellEditorListener);
1769 cellEditor = newEditor;
1770 if(cellEditorListener == null)
1771 cellEditorListener = createCellEditorListener();
1772 if(newEditor != null && cellEditorListener != null)
1773 newEditor.addCellEditorListener(cellEditorListener);
1774 createdCellEditor = false;
1775 }
1776 }
1777
1778
1779
1780
1781 protected void updateRenderer() {
1782 if(tree != null) {
1783 TreeCellRenderer newCellRenderer;
1784
1785 newCellRenderer = tree.getCellRenderer();
1786 if(newCellRenderer == null) {
1787 tree.setCellRenderer(createDefaultCellRenderer());
1788 createdRenderer = true;
1789 }
1790 else {
1791 createdRenderer = false;
1792 currentCellRenderer = newCellRenderer;
1793 if(createdCellEditor) {
1794 tree.setCellEditor(null);
1795 }
1796 }
1797 }
1798 else {
1799 createdRenderer = false;
1800 currentCellRenderer = null;
1801 }
1802 updateCellEditor();
1803 }
1804
1805
1806
1807
1808
1809 protected void configureLayoutCache() {
1810 if(treeState != null && tree != null) {
1811 if(nodeDimensions == null)
1812 nodeDimensions = createNodeDimensions();
1813 treeState.setNodeDimensions(nodeDimensions);
1814 treeState.setRootVisible(tree.isRootVisible());
1815 treeState.setRowHeight(tree.getRowHeight());
1816 treeState.setSelectionModel(getSelectionModel());
1817
1818
1819 if(treeState.getModel() != tree.getModel())
1820 treeState.setModel(tree.getModel());
1821 updateLayoutCacheExpandedNodesIfNecessary();
1822
1823
1824 if(isLargeModel()) {
1825 if(componentListener == null) {
1826 componentListener = createComponentListener();
1827 if(componentListener != null)
1828 tree.addComponentListener(componentListener);
1829 }
1830 }
1831 else if(componentListener != null) {
1832 tree.removeComponentListener(componentListener);
1833 componentListener = null;
1834 }
1835 }
1836 else if(componentListener != null) {
1837 tree.removeComponentListener(componentListener);
1838 componentListener = null;
1839 }
1840 }
1841
1842
1843
1844
1845
1846 protected void updateSize() {
1847 validCachedPreferredSize = false;
1848 tree.treeDidChange();
1849 }
1850
1851 private void updateSize0() {
1852 validCachedPreferredSize = false;
1853 tree.revalidate();
1854 }
1855
1856
1857
1858
1859
1860
1861
1862
1863 protected void updateCachedPreferredSize() {
1864 if(treeState != null) {
1865 Insets i = tree.getInsets();
1866
1867 if(isLargeModel()) {
1868 Rectangle visRect = tree.getVisibleRect();
1869
1870 if (visRect.x == 0 && visRect.y == 0 &&
1871 visRect.width == 0 && visRect.height == 0 &&
1872 tree.getVisibleRowCount() > 0) {
1873
1874
1875 visRect.width = 1;
1876 visRect.height = tree.getRowHeight() *
1877 tree.getVisibleRowCount();
1878 } else {
1879 visRect.x -= i.left;
1880 visRect.y -= i.top;
1881 }
1882 preferredSize.width = treeState.getPreferredWidth(visRect);
1883 }
1884 else {
1885 preferredSize.width = treeState.getPreferredWidth(null);
1886 }
1887 preferredSize.height = treeState.getPreferredHeight();
1888 preferredSize.width += i.left + i.right;
1889 preferredSize.height += i.top + i.bottom;
1890 }
1891 validCachedPreferredSize = true;
1892 }
1893
1894
1895
1896
1897 protected void pathWasExpanded(TreePath path) {
1898 if(tree != null) {
1899 tree.fireTreeExpanded(path);
1900 }
1901 }
1902
1903
1904
1905
1906 protected void pathWasCollapsed(TreePath path) {
1907 if(tree != null) {
1908 tree.fireTreeCollapsed(path);
1909 }
1910 }
1911
1912
1913
1914
1915
1916 protected void ensureRowsAreVisible(int beginRow, int endRow) {
1917 if(tree != null && beginRow >= 0 && endRow < getRowCount(tree)) {
1918 boolean scrollVert = DefaultLookup.getBoolean(tree, this,
1919 "Tree.scrollsHorizontallyAndVertically", false);
1920 if(beginRow == endRow) {
1921 Rectangle scrollBounds = getPathBounds(tree, getPathForRow
1922 (tree, beginRow));
1923
1924 if(scrollBounds != null) {
1925 if (!scrollVert) {
1926 scrollBounds.x = tree.getVisibleRect().x;
1927 scrollBounds.width = 1;
1928 }
1929 tree.scrollRectToVisible(scrollBounds);
1930 }
1931 }
1932 else {
1933 Rectangle beginRect = getPathBounds(tree, getPathForRow
1934 (tree, beginRow));
1935 Rectangle visRect = tree.getVisibleRect();
1936 Rectangle testRect = beginRect;
1937 int beginY = beginRect.y;
1938 int maxY = beginY + visRect.height;
1939
1940 for(int counter = beginRow + 1; counter <= endRow; counter++) {
1941 testRect = getPathBounds(tree,
1942 getPathForRow(tree, counter));
1943 if((testRect.y + testRect.height) > maxY)
1944 counter = endRow;
1945 }
1946 tree.scrollRectToVisible(new Rectangle(visRect.x, beginY, 1,
1947 testRect.y + testRect.height-
1948 beginY));
1949 }
1950 }
1951 }
1952
1953
1954
1955 public void setPreferredMinSize(Dimension newSize) {
1956 preferredMinSize = newSize;
1957 }
1958
1959
1960
1961 public Dimension getPreferredMinSize() {
1962 if(preferredMinSize == null)
1963 return null;
1964 return new Dimension(preferredMinSize);
1965 }
1966
1967
1968
1969
1970 public Dimension getPreferredSize(JComponent c) {
1971 return getPreferredSize(c, true);
1972 }
1973
1974
1975
1976
1977
1978 public Dimension getPreferredSize(JComponent c,
1979 boolean checkConsistency) {
1980 Dimension pSize = this.getPreferredMinSize();
1981
1982 if(!validCachedPreferredSize)
1983 updateCachedPreferredSize();
1984 if(tree != null) {
1985 if(pSize != null)
1986 return new Dimension(Math.max(pSize.width,
1987 preferredSize.width),
1988 Math.max(pSize.height, preferredSize.height));
1989 return new Dimension(preferredSize.width, preferredSize.height);
1990 }
1991 else if(pSize != null)
1992 return pSize;
1993 else
1994 return new Dimension(0, 0);
1995 }
1996
1997
1998
1999
2000
2001 public Dimension getMinimumSize(JComponent c) {
2002 if(this.getPreferredMinSize() != null)
2003 return this.getPreferredMinSize();
2004 return new Dimension(0, 0);
2005 }
2006
2007
2008
2009
2010
2011 public Dimension getMaximumSize(JComponent c) {
2012 if(tree != null)
2013 return getPreferredSize(tree);
2014 if(this.getPreferredMinSize() != null)
2015 return this.getPreferredMinSize();
2016 return new Dimension(0, 0);
2017 }
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028 protected void completeEditing() {
2029
2030 if(tree.getInvokesStopCellEditing() &&
2031 stopEditingInCompleteEditing && editingComponent != null) {
2032 cellEditor.stopCellEditing();
2033 }
2034
2035
2036 completeEditing(false, true, false);
2037 }
2038
2039
2040
2041
2042
2043
2044
2045 protected void completeEditing(boolean messageStop,
2046 boolean messageCancel,
2047 boolean messageTree) {
2048 if(stopEditingInCompleteEditing && editingComponent != null) {
2049 Component oldComponent = editingComponent;
2050 TreePath oldPath = editingPath;
2051 TreeCellEditor oldEditor = cellEditor;
2052 Object newValue = oldEditor.getCellEditorValue();
2053 Rectangle editingBounds = getPathBounds(tree,
2054 editingPath);
2055 boolean requestFocus = (tree != null &&
2056 (tree.hasFocus() || SwingUtilities.
2057 findFocusOwner(editingComponent) != null));
2058
2059 editingComponent = null;
2060 editingPath = null;
2061 if(messageStop)
2062 oldEditor.stopCellEditing();
2063 else if(messageCancel)
2064 oldEditor.cancelCellEditing();
2065 tree.remove(oldComponent);
2066 if(editorHasDifferentSize) {
2067 treeState.invalidatePathBounds(oldPath);
2068 updateSize();
2069 }
2070 else {
2071 editingBounds.x = 0;
2072 editingBounds.width = tree.getSize().width;
2073 tree.repaint(editingBounds);
2074 }
2075 if(requestFocus)
2076 tree.requestFocus();
2077 if(messageTree)
2078 treeModel.valueForPathChanged(oldPath, newValue);
2079 }
2080 }
2081
2082
2083
2084 private boolean startEditingOnRelease(TreePath path,
2085 MouseEvent event,
2086 MouseEvent releaseEvent) {
2087 this.releaseEvent = releaseEvent;
2088 try {
2089 return startEditing(path, event);
2090 } finally {
2091 this.releaseEvent = null;
2092 }
2093 }
2094
2095
2096
2097
2098
2099
2100 protected boolean startEditing(TreePath path, MouseEvent event) {
2101 if (isEditing(tree) && tree.getInvokesStopCellEditing() &&
2102 !stopEditing(tree)) {
2103 return false;
2104 }
2105 completeEditing();
2106 if(cellEditor != null && tree.isPathEditable(path)) {
2107 int row = getRowForPath(tree, path);
2108
2109 if(cellEditor.isCellEditable(event)) {
2110 editingComponent = cellEditor.getTreeCellEditorComponent
2111 (tree, path.getLastPathComponent(),
2112 tree.isPathSelected(path), tree.isExpanded(path),
2113 treeModel.isLeaf(path.getLastPathComponent()), row);
2114 Rectangle nodeBounds = getPathBounds(tree, path);
2115
2116 editingRow = row;
2117
2118 Dimension editorSize = editingComponent.getPreferredSize();
2119
2120
2121 if(editorSize.height != nodeBounds.height &&
2122 getRowHeight() > 0)
2123 editorSize.height = getRowHeight();
2124
2125 if(editorSize.width != nodeBounds.width ||
2126 editorSize.height != nodeBounds.height) {
2127
2128
2129 editorHasDifferentSize = true;
2130 treeState.invalidatePathBounds(path);
2131 updateSize();
2132
2133
2134 nodeBounds = getPathBounds(tree, path);
2135 }
2136 else
2137 editorHasDifferentSize = false;
2138 tree.add(editingComponent);
2139 editingComponent.setBounds(nodeBounds.x, nodeBounds.y,
2140 nodeBounds.width,
2141 nodeBounds.height);
2142 editingPath = path;
2143 if (editingComponent instanceof JComponent) {
2144 ((JComponent)editingComponent).revalidate();
2145 } else {
2146 editingComponent.validate();
2147 }
2148 editingComponent.repaint();
2149 if(cellEditor.shouldSelectCell(event)) {
2150 stopEditingInCompleteEditing = false;
2151 tree.setSelectionRow(row);
2152 stopEditingInCompleteEditing = true;
2153 }
2154
2155 Component focusedComponent = SwingUtilities2.
2156 compositeRequestFocus(editingComponent);
2157 boolean selectAll = true;
2158
2159 if(event != null) {
2160
2161
2162 Point componentPoint = SwingUtilities.convertPoint
2163 (tree, new Point(event.getX(), event.getY()),
2164 editingComponent);
2165
2166
2167
2168
2169
2170
2171 Component activeComponent = SwingUtilities.
2172 getDeepestComponentAt(editingComponent,
2173 componentPoint.x, componentPoint.y);
2174 if (activeComponent != null) {
2175 MouseInputHandler handler =
2176 new MouseInputHandler(tree, activeComponent,
2177 event, focusedComponent);
2178
2179 if (releaseEvent != null) {
2180 handler.mouseReleased(releaseEvent);
2181 }
2182
2183 selectAll = false;
2184 }
2185 }
2186 if (selectAll && focusedComponent instanceof JTextField) {
2187 ((JTextField)focusedComponent).selectAll();
2188 }
2189 return true;
2190 }
2191 else
2192 editingComponent = null;
2193 }
2194 return false;
2195 }
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206 protected void checkForClickInExpandControl(TreePath path,
2207 int mouseX, int mouseY) {
2208 if (isLocationInExpandControl(path, mouseX, mouseY)) {
2209 handleExpandControlClick(path, mouseX, mouseY);
2210 }
2211 }
2212
2213
2214
2215
2216
2217
2218 protected boolean isLocationInExpandControl(TreePath path,
2219 int mouseX, int mouseY) {
2220 if(path != null && !treeModel.isLeaf(path.getLastPathComponent())){
2221 int boxWidth;
2222 Insets i = tree.getInsets();
2223
2224 if(getExpandedIcon() != null)
2225 boxWidth = getExpandedIcon().getIconWidth();
2226 else
2227 boxWidth = 8;
2228
2229 int boxLeftX = getRowX(tree.getRowForPath(path),
2230 path.getPathCount() - 1);
2231
2232 if (leftToRight) {
2233 boxLeftX = boxLeftX + i.left - getRightChildIndent() + 1;
2234 } else {
2235 boxLeftX = tree.getWidth() - boxLeftX - i.right + getRightChildIndent() - 1;
2236 }
2237
2238 boxLeftX = findCenteredX(boxLeftX, boxWidth);
2239
2240 return (mouseX >= boxLeftX && mouseX < (boxLeftX + boxWidth));
2241 }
2242 return false;
2243 }
2244
2245
2246
2247
2248
2249 protected void handleExpandControlClick(TreePath path, int mouseX,
2250 int mouseY) {
2251 toggleExpandState(path);
2252 }
2253
2254
2255
2256
2257
2258
2259
2260 protected void toggleExpandState(TreePath path) {
2261 if(!tree.isExpanded(path)) {
2262 int row = getRowForPath(tree, path);
2263
2264 tree.expandPath(path);
2265 updateSize();
2266 if(row != -1) {
2267 if(tree.getScrollsOnExpand())
2268 ensureRowsAreVisible(row, row + treeState.
2269 getVisibleChildCount(path));
2270 else
2271 ensureRowsAreVisible(row, row);
2272 }
2273 }
2274 else {
2275 tree.collapsePath(path);
2276 updateSize();
2277 }
2278 }
2279
2280
2281
2282
2283
2284 protected boolean isToggleSelectionEvent(MouseEvent event) {
2285 return (SwingUtilities.isLeftMouseButton(event) &&
2286 BasicGraphicsUtils.isMenuShortcutKeyDown(event));
2287 }
2288
2289
2290
2291
2292
2293 protected boolean isMultiSelectEvent(MouseEvent event) {
2294 return (SwingUtilities.isLeftMouseButton(event) &&
2295 event.isShiftDown());
2296 }
2297
2298
2299
2300
2301
2302
2303 protected boolean isToggleEvent(MouseEvent event) {
2304 if(!SwingUtilities.isLeftMouseButton(event)) {
2305 return false;
2306 }
2307 int clickCount = tree.getToggleClickCount();
2308
2309 if(clickCount <= 0) {
2310 return false;
2311 }
2312 return ((event.getClickCount() % clickCount) == 0);
2313 }
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323 protected void selectPathForEvent(TreePath path, MouseEvent event) {
2324
2325 if(isMultiSelectEvent(event)) {
2326 TreePath anchor = getAnchorSelectionPath();
2327 int anchorRow = (anchor == null) ? -1 :
2328 getRowForPath(tree, anchor);
2329
2330 if(anchorRow == -1 || tree.getSelectionModel().
2331 getSelectionMode() == TreeSelectionModel.
2332 SINGLE_TREE_SELECTION) {
2333 tree.setSelectionPath(path);
2334 }
2335 else {
2336 int row = getRowForPath(tree, path);
2337 TreePath lastAnchorPath = anchor;
2338
2339 if (isToggleSelectionEvent(event)) {
2340 if (tree.isRowSelected(anchorRow)) {
2341 tree.addSelectionInterval(anchorRow, row);
2342 } else {
2343 tree.removeSelectionInterval(anchorRow, row);
2344 tree.addSelectionInterval(row, row);
2345 }
2346 } else if(row < anchorRow) {
2347 tree.setSelectionInterval(row, anchorRow);
2348 } else {
2349 tree.setSelectionInterval(anchorRow, row);
2350 }
2351 lastSelectedRow = row;
2352 setAnchorSelectionPath(lastAnchorPath);
2353 setLeadSelectionPath(path);
2354 }
2355 }
2356
2357
2358
2359 else if(isToggleSelectionEvent(event)) {
2360 if(tree.isPathSelected(path))
2361 tree.removeSelectionPath(path);
2362 else
2363 tree.addSelectionPath(path);
2364 lastSelectedRow = getRowForPath(tree, path);
2365 setAnchorSelectionPath(path);
2366 setLeadSelectionPath(path);
2367 }
2368
2369
2370 else if(SwingUtilities.isLeftMouseButton(event)) {
2371 tree.setSelectionPath(path);
2372 if(isToggleEvent(event)) {
2373 toggleExpandState(path);
2374 }
2375 }
2376 }
2377
2378
2379
2380
2381 protected boolean isLeaf(int row) {
2382 TreePath path = getPathForRow(tree, row);
2383
2384 if(path != null)
2385 return treeModel.isLeaf(path.getLastPathComponent());
2386
2387 return true;
2388 }
2389
2390
2391
2392
2393
2394 private void setAnchorSelectionPath(TreePath newPath) {
2395 ignoreLAChange = true;
2396 try {
2397 tree.setAnchorSelectionPath(newPath);
2398 } finally{
2399 ignoreLAChange = false;
2400 }
2401 }
2402
2403 private TreePath getAnchorSelectionPath() {
2404 return tree.getAnchorSelectionPath();
2405 }
2406
2407 private void setLeadSelectionPath(TreePath newPath) {
2408 setLeadSelectionPath(newPath, false);
2409 }
2410
2411 private void setLeadSelectionPath(TreePath newPath, boolean repaint) {
2412 Rectangle bounds = repaint ?
2413 getPathBounds(tree, getLeadSelectionPath()) : null;
2414
2415 ignoreLAChange = true;
2416 try {
2417 tree.setLeadSelectionPath(newPath);
2418 } finally {
2419 ignoreLAChange = false;
2420 }
2421 leadRow = getRowForPath(tree, newPath);
2422
2423 if (repaint) {
2424 if (bounds != null) {
2425 tree.repaint(getRepaintPathBounds(bounds));
2426 }
2427 bounds = getPathBounds(tree, newPath);
2428 if (bounds != null) {
2429 tree.repaint(getRepaintPathBounds(bounds));
2430 }
2431 }
2432 }
2433
2434 private Rectangle getRepaintPathBounds(Rectangle bounds) {
2435 if (UIManager.getBoolean("Tree.repaintWholeRow")) {
2436 bounds.x = 0;
2437 bounds.width = tree.getWidth();
2438 }
2439 return bounds;
2440 }
2441
2442 private TreePath getLeadSelectionPath() {
2443 return tree.getLeadSelectionPath();
2444 }
2445
2446
2447
2448
2449
2450 protected void updateLeadSelectionRow() {
2451 leadRow = getRowForPath(tree, getLeadSelectionPath());
2452 }
2453
2454
2455
2456
2457
2458
2459
2460 protected int getLeadSelectionRow() {
2461 return leadRow;
2462 }
2463
2464
2465
2466
2467
2468 private void extendSelection(TreePath newLead) {
2469 TreePath aPath = getAnchorSelectionPath();
2470 int aRow = (aPath == null) ? -1 :
2471 getRowForPath(tree, aPath);
2472 int newIndex = getRowForPath(tree, newLead);
2473
2474 if(aRow == -1) {
2475 tree.setSelectionRow(newIndex);
2476 }
2477 else {
2478 if(aRow < newIndex) {
2479 tree.setSelectionInterval(aRow, newIndex);
2480 }
2481 else {
2482 tree.setSelectionInterval(newIndex, aRow);
2483 }
2484 setAnchorSelectionPath(aPath);
2485 setLeadSelectionPath(newLead);
2486 }
2487 }
2488
2489
2490
2491
2492
2493 private void repaintPath(TreePath path) {
2494 if (path != null) {
2495 Rectangle bounds = getPathBounds(tree, path);
2496 if (bounds != null) {
2497 tree.repaint(bounds.x, bounds.y, bounds.width, bounds.height);
2498 }
2499 }
2500 }
2501
2502
2503
2504
2505 public class TreeExpansionHandler implements TreeExpansionListener {
2506
2507
2508
2509
2510
2511
2512
2513
2514 public void treeExpanded(TreeExpansionEvent event) {
2515 getHandler().treeExpanded(event);
2516 }
2517
2518
2519
2520
2521 public void treeCollapsed(TreeExpansionEvent event) {
2522 getHandler().treeCollapsed(event);
2523 }
2524 }
2525
2526
2527
2528
2529
2530 public class ComponentHandler extends ComponentAdapter implements
2531 ActionListener {
2532
2533
2534 protected Timer timer;
2535
2536 protected JScrollBar scrollBar;
2537
2538 public void componentMoved(ComponentEvent e) {
2539 if(timer == null) {
2540 JScrollPane scrollPane = getScrollPane();
2541
2542 if(scrollPane == null)
2543 updateSize();
2544 else {
2545 scrollBar = scrollPane.getVerticalScrollBar();
2546 if(scrollBar == null ||
2547 !scrollBar.getValueIsAdjusting()) {
2548
2549 if((scrollBar = scrollPane.getHorizontalScrollBar())
2550 != null && scrollBar.getValueIsAdjusting())
2551 startTimer();
2552 else
2553 updateSize();
2554 }
2555 else
2556 startTimer();
2557 }
2558 }
2559 }
2560
2561
2562
2563
2564
2565 protected void startTimer() {
2566 if(timer == null) {
2567 timer = new Timer(200, this);
2568 timer.setRepeats(true);
2569 }
2570 timer.start();
2571 }
2572
2573
2574
2575
2576
2577 protected JScrollPane getScrollPane() {
2578 Component c = tree.getParent();
2579
2580 while(c != null && !(c instanceof JScrollPane))
2581 c = c.getParent();
2582 if(c instanceof JScrollPane)
2583 return (JScrollPane)c;
2584 return null;
2585 }
2586
2587
2588
2589
2590
2591 public void actionPerformed(ActionEvent ae) {
2592 if(scrollBar == null || !scrollBar.getValueIsAdjusting()) {
2593 if(timer != null)
2594 timer.stop();
2595 updateSize();
2596 timer = null;
2597 scrollBar = null;
2598 }
2599 }
2600 }
2601
2602
2603
2604
2605
2606 public class TreeModelHandler implements TreeModelListener {
2607
2608
2609
2610
2611
2612
2613 public void treeNodesChanged(TreeModelEvent e) {
2614 getHandler().treeNodesChanged(e);
2615 }
2616
2617 public void treeNodesInserted(TreeModelEvent e) {
2618 getHandler().treeNodesInserted(e);
2619 }
2620
2621 public void treeNodesRemoved(TreeModelEvent e) {
2622 getHandler().treeNodesRemoved(e);
2623 }
2624
2625 public void treeStructureChanged(TreeModelEvent e) {
2626 getHandler().treeStructureChanged(e);
2627 }
2628 }
2629
2630
2631
2632
2633
2634
2635 public class TreeSelectionHandler implements TreeSelectionListener {
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646 public void valueChanged(TreeSelectionEvent event) {
2647 getHandler().valueChanged(event);
2648 }
2649 }
2650
2651
2652
2653
2654
2655
2656 public class CellEditorHandler implements CellEditorListener {
2657
2658
2659
2660
2661
2662
2663
2664 public void editingStopped(ChangeEvent e) {
2665 getHandler().editingStopped(e);
2666 }
2667
2668
2669 public void editingCanceled(ChangeEvent e) {
2670 getHandler().editingCanceled(e);
2671 }
2672 }
2673
2674
2675
2676
2677
2678
2679 public class KeyHandler extends KeyAdapter {
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691 protected Action repeatKeyAction;
2692
2693
2694 protected boolean isKeyDown;
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705 public void keyTyped(KeyEvent e) {
2706 getHandler().keyTyped(e);
2707 }
2708
2709 public void keyPressed(KeyEvent e) {
2710 getHandler().keyPressed(e);
2711 }
2712
2713 public void keyReleased(KeyEvent e) {
2714 getHandler().keyReleased(e);
2715 }
2716 }
2717
2718
2719
2720
2721
2722 public class FocusHandler implements FocusListener {
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732 public void focusGained(FocusEvent e) {
2733 getHandler().focusGained(e);
2734 }
2735
2736
2737
2738
2739
2740 public void focusLost(FocusEvent e) {
2741 getHandler().focusLost(e);
2742 }
2743 }
2744
2745
2746
2747
2748
2749
2750
2751
2752 public class NodeDimensionsHandler extends
2753 AbstractLayoutCache.NodeDimensions {
2754
2755
2756
2757 public Rectangle getNodeDimensions(Object value, int row,
2758 int depth, boolean expanded,
2759 Rectangle size) {
2760
2761
2762 if(editingComponent != null && editingRow == row) {
2763 Dimension prefSize = editingComponent.
2764 getPreferredSize();
2765 int rh = getRowHeight();
2766
2767 if(rh > 0 && rh != prefSize.height)
2768 prefSize.height = rh;
2769 if(size != null) {
2770 size.x = getRowX(row, depth);
2771 size.width = prefSize.width;
2772 size.height = prefSize.height;
2773 }
2774 else {
2775 size = new Rectangle(getRowX(row, depth), 0,
2776 prefSize.width, prefSize.height);
2777 }
2778 return size;
2779 }
2780
2781 if(currentCellRenderer != null) {
2782 Component aComponent;
2783
2784 aComponent = currentCellRenderer.getTreeCellRendererComponent
2785 (tree, value, tree.isRowSelected(row),
2786 expanded, treeModel.isLeaf(value), row,
2787 false);
2788 if(tree != null) {
2789
2790 rendererPane.add(aComponent);
2791 aComponent.validate();
2792 }
2793 Dimension prefSize = aComponent.getPreferredSize();
2794
2795 if(size != null) {
2796 size.x = getRowX(row, depth);
2797 size.width = prefSize.width;
2798 size.height = prefSize.height;
2799 }
2800 else {
2801 size = new Rectangle(getRowX(row, depth), 0,
2802 prefSize.width, prefSize.height);
2803 }
2804 return size;
2805 }
2806 return null;
2807 }
2808
2809
2810
2811
2812 protected int getRowX(int row, int depth) {
2813 return BasicTreeUI.this.getRowX(row, depth);
2814 }
2815
2816 }
2817
2818
2819
2820
2821
2822
2823 public class MouseHandler extends MouseAdapter implements MouseMotionListener
2824 {
2825
2826
2827
2828
2829
2830
2831
2832
2833 public void mousePressed(MouseEvent e) {
2834 getHandler().mousePressed(e);
2835 }
2836
2837 public void mouseDragged(MouseEvent e) {
2838 getHandler().mouseDragged(e);
2839 }
2840
2841
2842
2843
2844
2845
2846 public void mouseMoved(MouseEvent e) {
2847 getHandler().mouseMoved(e);
2848 }
2849
2850 public void mouseReleased(MouseEvent e) {
2851 getHandler().mouseReleased(e);
2852 }
2853 }
2854
2855
2856
2857
2858
2859
2860 public class PropertyChangeHandler implements
2861 PropertyChangeListener {
2862
2863
2864
2865
2866
2867
2868 public void propertyChange(PropertyChangeEvent event) {
2869 getHandler().propertyChange(event);
2870 }
2871 }
2872
2873
2874
2875
2876
2877
2878 public class SelectionModelPropertyChangeHandler implements
2879 PropertyChangeListener {
2880
2881
2882
2883
2884
2885
2886 public void propertyChange(PropertyChangeEvent event) {
2887 getHandler().propertyChange(event);
2888 }
2889 }
2890
2891
2892
2893
2894
2895
2896
2897 public class TreeTraverseAction extends AbstractAction {
2898
2899
2900 protected int direction;
2901
2902
2903 private boolean changeSelection;
2904
2905 public TreeTraverseAction(int direction, String name) {
2906 this(direction, name, true);
2907 }
2908
2909 private TreeTraverseAction(int direction, String name,
2910 boolean changeSelection) {
2911 this.direction = direction;
2912 this.changeSelection = changeSelection;
2913 }
2914
2915 public void actionPerformed(ActionEvent e) {
2916 if (tree != null) {
2917 SHARED_ACTION.traverse(tree, BasicTreeUI.this, direction,
2918 changeSelection);
2919 }
2920 }
2921
2922 public boolean isEnabled() { return (tree != null &&
2923 tree.isEnabled()); }
2924 }
2925
2926
2927
2928
2929 public class TreePageAction extends AbstractAction {
2930
2931 protected int direction;
2932
2933 private boolean addToSelection;
2934 private boolean changeSelection;
2935
2936 public TreePageAction(int direction, String name) {
2937 this(direction, name, false, true);
2938 }
2939
2940 private TreePageAction(int direction, String name,
2941 boolean addToSelection,
2942 boolean changeSelection) {
2943 this.direction = direction;
2944 this.addToSelection = addToSelection;
2945 this.changeSelection = changeSelection;
2946 }
2947
2948 public void actionPerformed(ActionEvent e) {
2949 if (tree != null) {
2950 SHARED_ACTION.page(tree, BasicTreeUI.this, direction,
2951 addToSelection, changeSelection);
2952 }
2953 }
2954
2955 public boolean isEnabled() { return (tree != null &&
2956 tree.isEnabled()); }
2957
2958 }
2959
2960
2961
2962
2963
2964 public class TreeIncrementAction extends AbstractAction {
2965
2966 protected int direction;
2967
2968
2969 private boolean addToSelection;
2970 private boolean changeSelection;
2971
2972 public TreeIncrementAction(int direction, String name) {
2973 this(direction, name, false, true);
2974 }
2975
2976 private TreeIncrementAction(int direction, String name,
2977 boolean addToSelection,
2978 boolean changeSelection) {
2979 this.direction = direction;
2980 this.addToSelection = addToSelection;
2981 this.changeSelection = changeSelection;
2982 }
2983
2984 public void actionPerformed(ActionEvent e) {
2985 if (tree != null) {
2986 SHARED_ACTION.increment(tree, BasicTreeUI.this, direction,
2987 addToSelection, changeSelection);
2988 }
2989 }
2990
2991 public boolean isEnabled() { return (tree != null &&
2992 tree.isEnabled()); }
2993
2994 }
2995
2996
2997
2998
2999
3000
3001 public class TreeHomeAction extends AbstractAction {
3002 protected int direction;
3003
3004 private boolean addToSelection;
3005 private boolean changeSelection;
3006
3007 public TreeHomeAction(int direction, String name) {
3008 this(direction, name, false, true);
3009 }
3010
3011 private TreeHomeAction(int direction, String name,
3012 boolean addToSelection,
3013 boolean changeSelection) {
3014 this.direction = direction;
3015 this.changeSelection = changeSelection;
3016 this.addToSelection = addToSelection;
3017 }
3018
3019 public void actionPerformed(ActionEvent e) {
3020 if (tree != null) {
3021 SHARED_ACTION.home(tree, BasicTreeUI.this, direction,
3022 addToSelection, changeSelection);
3023 }
3024 }
3025
3026 public boolean isEnabled() { return (tree != null &&
3027 tree.isEnabled()); }
3028
3029 }
3030
3031
3032
3033
3034
3035 public class TreeToggleAction extends AbstractAction {
3036 public TreeToggleAction(String name) {
3037 }
3038
3039 public void actionPerformed(ActionEvent e) {
3040 if(tree != null) {
3041 SHARED_ACTION.toggle(tree, BasicTreeUI.this);
3042 }
3043 }
3044
3045 public boolean isEnabled() { return (tree != null &&
3046 tree.isEnabled()); }
3047
3048 }
3049
3050
3051
3052
3053
3054 public class TreeCancelEditingAction extends AbstractAction {
3055 public TreeCancelEditingAction(String name) {
3056 }
3057
3058 public void actionPerformed(ActionEvent e) {
3059 if(tree != null) {
3060 SHARED_ACTION.cancelEditing(tree, BasicTreeUI.this);
3061 }
3062 }
3063
3064 public boolean isEnabled() { return (tree != null &&
3065 tree.isEnabled() &&
3066 isEditing(tree)); }
3067 }
3068
3069
3070
3071
3072
3073
3074
3075
3076 public class MouseInputHandler extends Object implements
3077 MouseInputListener
3078 {
3079
3080 protected Component source;
3081
3082 protected Component destination;
3083 private Component focusComponent;
3084 private boolean dispatchedEvent;
3085
3086 public MouseInputHandler(Component source, Component destination,
3087 MouseEvent event){
3088 this(source, destination, event, null);
3089 }
3090
3091 MouseInputHandler(Component source, Component destination,
3092 MouseEvent event, Component focusComponent) {
3093 this.source = source;
3094 this.destination = destination;
3095 this.source.addMouseListener(this);
3096 this.source.addMouseMotionListener(this);
3097
3098 SwingUtilities2.setSkipClickCount(destination,
3099 event.getClickCount() - 1);
3100
3101
3102 destination.dispatchEvent(SwingUtilities.convertMouseEvent
3103 (source, event, destination));
3104 this.focusComponent = focusComponent;
3105 }
3106
3107 public void mouseClicked(MouseEvent e) {
3108 if(destination != null) {
3109 dispatchedEvent = true;
3110 destination.dispatchEvent(SwingUtilities.convertMouseEvent
3111 (source, e, destination));
3112 }
3113 }
3114
3115 public void mousePressed(MouseEvent e) {
3116 }
3117
3118 public void mouseReleased(MouseEvent e) {
3119 if(destination != null)
3120 destination.dispatchEvent(SwingUtilities.convertMouseEvent
3121 (source, e, destination));
3122 removeFromSource();
3123 }
3124
3125 public void mouseEntered(MouseEvent e) {
3126 if (!SwingUtilities.isLeftMouseButton(e)) {
3127 removeFromSource();
3128 }
3129 }
3130
3131 public void mouseExited(MouseEvent e) {
3132 if (!SwingUtilities.isLeftMouseButton(e)) {
3133 removeFromSource();
3134 }
3135 }
3136
3137 public void mouseDragged(MouseEvent e) {
3138 if(destination != null) {
3139 dispatchedEvent = true;
3140 destination.dispatchEvent(SwingUtilities.convertMouseEvent
3141 (source, e, destination));
3142 }
3143 }
3144
3145 public void mouseMoved(MouseEvent e) {
3146 removeFromSource();
3147 }
3148
3149 protected void removeFromSource() {
3150 if(source != null) {
3151 source.removeMouseListener(this);
3152 source.removeMouseMotionListener(this);
3153 if (focusComponent != null &&
3154 focusComponent == destination && !dispatchedEvent &&
3155 (focusComponent instanceof JTextField)) {
3156 ((JTextField)focusComponent).selectAll();
3157 }
3158 }
3159 source = destination = null;
3160 }
3161
3162 }
3163
3164 private static final TransferHandler defaultTransferHandler = new TreeTransferHandler();
3165
3166 static class TreeTransferHandler extends TransferHandler implements UIResource, Comparator<TreePath> {
3167
3168 private JTree tree;
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179 protected Transferable createTransferable(JComponent c) {
3180 if (c instanceof JTree) {
3181 tree = (JTree) c;
3182 TreePath[] paths = tree.getSelectionPaths();
3183
3184 if (paths == null || paths.length == 0) {
3185 return null;
3186 }
3187
3188 StringBuffer plainBuf = new StringBuffer();
3189 StringBuffer htmlBuf = new StringBuffer();
3190
3191 htmlBuf.append("<html>\n<body>\n<ul>\n");
3192
3193 TreeModel model = tree.getModel();
3194 TreePath lastPath = null;
3195 TreePath[] displayPaths = getDisplayOrderPaths(paths);
3196
3197 for (TreePath path : displayPaths) {
3198 Object node = path.getLastPathComponent();
3199 boolean leaf = model.isLeaf(node);
3200 String label = getDisplayString(path, true, leaf);
3201
3202 plainBuf.append(label + "\n");
3203 htmlBuf.append(" <li>" + label + "\n");
3204 }
3205
3206
3207 plainBuf.deleteCharAt(plainBuf.length() - 1);
3208 htmlBuf.append("</ul>\n</body>\n</html>");
3209
3210 tree = null;
3211
3212 return new BasicTransferable(plainBuf.toString(), htmlBuf.toString());
3213 }
3214
3215 return null;
3216 }
3217
3218 public int compare(TreePath o1, TreePath o2) {
3219 int row1 = tree.getRowForPath(o1);
3220 int row2 = tree.getRowForPath(o2);
3221 return row1 - row2;
3222 }
3223
3224 String getDisplayString(TreePath path, boolean selected, boolean leaf) {
3225 int row = tree.getRowForPath(path);
3226 boolean hasFocus = tree.getLeadSelectionRow() == row;
3227 Object node = path.getLastPathComponent();
3228 return tree.convertValueToText(node, selected, tree.isExpanded(row),
3229 leaf, row, hasFocus);
3230 }
3231
3232
3233
3234
3235
3236
3237 TreePath[] getDisplayOrderPaths(TreePath[] paths) {
3238
3239 ArrayList<TreePath> selOrder = new ArrayList<TreePath>();
3240 for (TreePath path : paths) {
3241 selOrder.add(path);
3242 }
3243 Collections.sort(selOrder, this);
3244 int n = selOrder.size();
3245 TreePath[] displayPaths = new TreePath[n];
3246 for (int i = 0; i < n; i++) {
3247 displayPaths[i] = selOrder.get(i);
3248 }
3249 return displayPaths;
3250 }
3251
3252 public int getSourceActions(JComponent c) {
3253 return COPY;
3254 }
3255
3256 }
3257
3258
3259 private class Handler implements CellEditorListener, FocusListener,
3260 KeyListener, MouseListener, MouseMotionListener,
3261 PropertyChangeListener, TreeExpansionListener,
3262 TreeModelListener, TreeSelectionListener,
3263 BeforeDrag {
3264
3265
3266
3267 private String prefix = "";
3268 private String typedString = "";
3269 private long lastTime = 0L;
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282 public void keyTyped(KeyEvent e) {
3283
3284 if(tree != null && tree.getRowCount()>0 && tree.hasFocus() &&
3285 tree.isEnabled()) {
3286 if (e.isAltDown() || BasicGraphicsUtils.isMenuShortcutKeyDown(e) ||
3287 isNavigationKey(e)) {
3288 return;
3289 }
3290 boolean startingFromSelection = true;
3291
3292 char c = e.getKeyChar();
3293
3294 long time = e.getWhen();
3295 int startingRow = tree.getLeadSelectionRow();
3296 if (time - lastTime < timeFactor) {
3297 typedString += c;
3298 if((prefix.length() == 1) && (c == prefix.charAt(0))) {
3299
3300
3301 startingRow++;
3302 } else {
3303 prefix = typedString;
3304 }
3305 } else {
3306 startingRow++;
3307 typedString = "" + c;
3308 prefix = typedString;
3309 }
3310 lastTime = time;
3311
3312 if (startingRow < 0 || startingRow >= tree.getRowCount()) {
3313 startingFromSelection = false;
3314 startingRow = 0;
3315 }
3316 TreePath path = tree.getNextMatch(prefix, startingRow,
3317 Position.Bias.Forward);
3318 if (path != null) {
3319 tree.setSelectionPath(path);
3320 int row = getRowForPath(tree, path);
3321 ensureRowsAreVisible(row, row);
3322 } else if (startingFromSelection) {
3323 path = tree.getNextMatch(prefix, 0,
3324 Position.Bias.Forward);
3325 if (path != null) {
3326 tree.setSelectionPath(path);
3327 int row = getRowForPath(tree, path);
3328 ensureRowsAreVisible(row, row);
3329 }
3330 }
3331 }
3332 }
3333
3334
3335
3336
3337
3338
3339
3340 public void keyPressed(KeyEvent e) {
3341 if (tree != null && isNavigationKey(e)) {
3342 prefix = "";
3343 typedString = "";
3344 lastTime = 0L;
3345 }
3346 }
3347
3348 public void keyReleased(KeyEvent e) {
3349 }
3350
3351
3352
3353
3354
3355
3356 private boolean isNavigationKey(KeyEvent event) {
3357 InputMap inputMap = tree.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
3358 KeyStroke key = KeyStroke.getKeyStrokeForEvent(event);
3359
3360 return inputMap != null && inputMap.get(key) != null;
3361 }
3362
3363
3364
3365
3366
3367 public void propertyChange(PropertyChangeEvent event) {
3368 if (event.getSource() == treeSelectionModel) {
3369 treeSelectionModel.resetRowSelection();
3370 }
3371 else if(event.getSource() == tree) {
3372 String changeName = event.getPropertyName();
3373
3374 if (changeName == JTree.LEAD_SELECTION_PATH_PROPERTY) {
3375 if (!ignoreLAChange) {
3376 updateLeadSelectionRow();
3377 repaintPath((TreePath)event.getOldValue());
3378 repaintPath((TreePath)event.getNewValue());
3379 }
3380 }
3381 else if (changeName == JTree.ANCHOR_SELECTION_PATH_PROPERTY) {
3382 if (!ignoreLAChange) {
3383 repaintPath((TreePath)event.getOldValue());
3384 repaintPath((TreePath)event.getNewValue());
3385 }
3386 }
3387 if(changeName == JTree.CELL_RENDERER_PROPERTY) {
3388 setCellRenderer((TreeCellRenderer)event.getNewValue());
3389 redoTheLayout();
3390 }
3391 else if(changeName == JTree.TREE_MODEL_PROPERTY) {
3392 setModel((TreeModel)event.getNewValue());
3393 }
3394 else if(changeName == JTree.ROOT_VISIBLE_PROPERTY) {
3395 setRootVisible(((Boolean)event.getNewValue()).
3396 booleanValue());
3397 }
3398 else if(changeName == JTree.SHOWS_ROOT_HANDLES_PROPERTY) {
3399 setShowsRootHandles(((Boolean)event.getNewValue()).
3400 booleanValue());
3401 }
3402 else if(changeName == JTree.ROW_HEIGHT_PROPERTY) {
3403 setRowHeight(((Integer)event.getNewValue()).
3404 intValue());
3405 }
3406 else if(changeName == JTree.CELL_EDITOR_PROPERTY) {
3407 setCellEditor((TreeCellEditor)event.getNewValue());
3408 }
3409 else if(changeName == JTree.EDITABLE_PROPERTY) {
3410 setEditable(((Boolean)event.getNewValue()).booleanValue());
3411 }
3412 else if(changeName == JTree.LARGE_MODEL_PROPERTY) {
3413 setLargeModel(tree.isLargeModel());
3414 }
3415 else if(changeName == JTree.SELECTION_MODEL_PROPERTY) {
3416 setSelectionModel(tree.getSelectionModel());
3417 }
3418 else if(changeName == "font") {
3419 completeEditing();
3420 if(treeState != null)
3421 treeState.invalidateSizes();
3422 updateSize();
3423 }
3424 else if (changeName == "componentOrientation") {
3425 if (tree != null) {
3426 leftToRight = BasicGraphicsUtils.isLeftToRight(tree);
3427 redoTheLayout();
3428 tree.treeDidChange();
3429
3430 InputMap km = getInputMap(JComponent.WHEN_FOCUSED);
3431 SwingUtilities.replaceUIInputMap(tree,
3432 JComponent.WHEN_FOCUSED, km);
3433 }
3434 } else if ("dropLocation" == changeName) {
3435 JTree.DropLocation oldValue = (JTree.DropLocation)event.getOldValue();
3436 repaintDropLocation(oldValue);
3437 repaintDropLocation(tree.getDropLocation());
3438 }
3439 }
3440 }
3441
3442 private void repaintDropLocation(JTree.DropLocation loc) {
3443 if (loc == null) {
3444 return;
3445 }
3446
3447 Rectangle r;
3448
3449 if (isDropLine(loc)) {
3450 r = getDropLineRect(loc);
3451 } else {
3452 r = tree.getPathBounds(loc.getPath());
3453 }
3454
3455 if (r != null) {
3456 tree.repaint(r);
3457 }
3458 }
3459
3460
3461
3462
3463
3464
3465
3466
3467 private boolean dragPressDidSelection;
3468
3469
3470
3471
3472 private boolean dragStarted;
3473
3474
3475 private TreePath pressedPath;
3476 private MouseEvent pressedEvent;
3477
3478
3479
3480 private boolean valueChangedOnPress;
3481
3482 private boolean isActualPath(TreePath path, int x, int y) {
3483 if (path == null) {
3484 return false;
3485 }
3486
3487 Rectangle bounds = getPathBounds(tree, path);
3488 if (y > (bounds.y + bounds.height)) {
3489 return false;
3490 }
3491
3492 return (x >= bounds.x) && (x <= (bounds.x + bounds.width));
3493 }
3494
3495 public void mouseClicked(MouseEvent e) {
3496 }
3497
3498 public void mouseEntered(MouseEvent e) {
3499 }
3500
3501 public void mouseExited(MouseEvent e) {
3502 }
3503
3504
3505
3506
3507 public void mousePressed(MouseEvent e) {
3508 if (SwingUtilities2.shouldIgnore(e, tree)) {
3509 return;
3510 }
3511
3512
3513 if (isEditing(tree) && tree.getInvokesStopCellEditing()
3514 && !stopEditing(tree)) {
3515 return;
3516 }
3517
3518 completeEditing();
3519
3520 pressedPath = getClosestPathForLocation(tree, e.getX(), e.getY());
3521
3522 if (tree.getDragEnabled()) {
3523 mousePressedDND(e);
3524 } else {
3525 SwingUtilities2.adjustFocus(tree);
3526 handleSelection(e);
3527 }
3528 }
3529
3530 private void mousePressedDND(MouseEvent e) {
3531 pressedEvent = e;
3532 boolean grabFocus = true;
3533 dragStarted = false;
3534 valueChangedOnPress = false;
3535
3536
3537 if (isActualPath(pressedPath, e.getX(), e.getY()) &&
3538 DragRecognitionSupport.mousePressed(e)) {
3539
3540 dragPressDidSelection = false;
3541
3542 if (BasicGraphicsUtils.isMenuShortcutKeyDown(e)) {
3543
3544
3545 return;
3546 } else if (!e.isShiftDown() && tree.isPathSelected(pressedPath)) {
3547
3548
3549 setAnchorSelectionPath(pressedPath);
3550 setLeadSelectionPath(pressedPath, true);
3551 return;
3552 }
3553
3554 dragPressDidSelection = true;
3555
3556
3557 grabFocus = false;
3558 }
3559
3560 if (grabFocus) {
3561 SwingUtilities2.adjustFocus(tree);
3562 }
3563
3564 handleSelection(e);
3565 }
3566
3567 void handleSelection(MouseEvent e) {
3568 if(pressedPath != null) {
3569 Rectangle bounds = getPathBounds(tree, pressedPath);
3570
3571 if(e.getY() >= (bounds.y + bounds.height)) {
3572 return;
3573 }
3574
3575
3576
3577 if(SwingUtilities.isLeftMouseButton(e)) {
3578 checkForClickInExpandControl(pressedPath, e.getX(), e.getY());
3579 }
3580
3581 int x = e.getX();
3582
3583
3584
3585 if (x >= bounds.x && x < (bounds.x + bounds.width)) {
3586 if (tree.getDragEnabled() || !startEditing(pressedPath, e)) {
3587 selectPathForEvent(pressedPath, e);
3588 }
3589 }
3590 }
3591 }
3592
3593 public void dragStarting(MouseEvent me) {
3594 dragStarted = true;
3595
3596 if (BasicGraphicsUtils.isMenuShortcutKeyDown(me)) {
3597 tree.addSelectionPath(pressedPath);
3598 setAnchorSelectionPath(pressedPath);
3599 setLeadSelectionPath(pressedPath, true);
3600 }
3601
3602 pressedEvent = null;
3603 pressedPath = null;
3604 }
3605
3606 public void mouseDragged(MouseEvent e) {
3607 if (SwingUtilities2.shouldIgnore(e, tree)) {
3608 return;
3609 }
3610
3611 if (tree.getDragEnabled()) {
3612 DragRecognitionSupport.mouseDragged(e, this);
3613 }
3614 }
3615
3616
3617
3618
3619
3620 public void mouseMoved(MouseEvent e) {
3621 }
3622
3623 public void mouseReleased(MouseEvent e) {
3624 if (SwingUtilities2.shouldIgnore(e, tree)) {
3625 return;
3626 }
3627
3628 if (tree.getDragEnabled()) {
3629 mouseReleasedDND(e);
3630 }
3631
3632 pressedEvent = null;
3633 pressedPath = null;
3634 }
3635
3636 private void mouseReleasedDND(MouseEvent e) {
3637 MouseEvent me = DragRecognitionSupport.mouseReleased(e);
3638 if (me != null) {
3639 SwingUtilities2.adjustFocus(tree);
3640 if (!dragPressDidSelection) {
3641 handleSelection(me);
3642 }
3643 }
3644
3645 if (!dragStarted) {
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656 if (pressedPath != null && !valueChangedOnPress &&
3657 isActualPath(pressedPath, pressedEvent.getX(), pressedEvent.getY())) {
3658
3659 startEditingOnRelease(pressedPath, pressedEvent, e);
3660 }
3661 }
3662 }
3663
3664
3665
3666
3667 public void focusGained(FocusEvent e) {
3668 if(tree != null) {
3669 Rectangle pBounds;
3670
3671 pBounds = getPathBounds(tree, tree.getLeadSelectionPath());
3672 if(pBounds != null)
3673 tree.repaint(getRepaintPathBounds(pBounds));
3674 pBounds = getPathBounds(tree, getLeadSelectionPath());
3675 if(pBounds != null)
3676 tree.repaint(getRepaintPathBounds(pBounds));
3677 }
3678 }
3679
3680 public void focusLost(FocusEvent e) {
3681 focusGained(e);
3682 }
3683
3684
3685
3686
3687 public void editingStopped(ChangeEvent e) {
3688 completeEditing(false, false, true);
3689 }
3690
3691
3692 public void editingCanceled(ChangeEvent e) {
3693 completeEditing(false, false, false);
3694 }
3695
3696
3697
3698
3699
3700 public void valueChanged(TreeSelectionEvent event) {
3701 valueChangedOnPress = true;
3702
3703
3704 completeEditing();
3705
3706
3707 if(tree.getExpandsSelectedPaths() && treeSelectionModel != null) {
3708 TreePath[] paths = treeSelectionModel
3709 .getSelectionPaths();
3710
3711 if(paths != null) {
3712 for(int counter = paths.length - 1; counter >= 0;
3713 counter--) {
3714 TreePath path = paths[counter].getParentPath();
3715 boolean expand = true;
3716
3717 while (path != null) {
3718
3719
3720 if (treeModel.isLeaf(path.getLastPathComponent())){
3721 expand = false;
3722 path = null;
3723 }
3724 else {
3725 path = path.getParentPath();
3726 }
3727 }
3728 if (expand) {
3729 tree.makeVisible(paths[counter]);
3730 }
3731 }
3732 }
3733 }
3734
3735 TreePath oldLead = getLeadSelectionPath();
3736 lastSelectedRow = tree.getMinSelectionRow();
3737 TreePath lead = tree.getSelectionModel().getLeadSelectionPath();
3738 setAnchorSelectionPath(lead);
3739 setLeadSelectionPath(lead);
3740
3741 TreePath[] changedPaths = event.getPaths();
3742 Rectangle nodeBounds;
3743 Rectangle visRect = tree.getVisibleRect();
3744 boolean paintPaths = true;
3745 int nWidth = tree.getWidth();
3746
3747 if(changedPaths != null) {
3748 int counter, maxCounter = changedPaths.length;
3749
3750 if(maxCounter > 4) {
3751 tree.repaint();
3752 paintPaths = false;
3753 }
3754 else {
3755 for (counter = 0; counter < maxCounter; counter++) {
3756 nodeBounds = getPathBounds(tree,
3757 changedPaths[counter]);
3758 if(nodeBounds != null &&
3759 visRect.intersects(nodeBounds))
3760 tree.repaint(0, nodeBounds.y, nWidth,
3761 nodeBounds.height);
3762 }
3763 }
3764 }
3765 if(paintPaths) {
3766 nodeBounds = getPathBounds(tree, oldLead);
3767 if(nodeBounds != null && visRect.intersects(nodeBounds))
3768 tree.repaint(0, nodeBounds.y, nWidth, nodeBounds.height);
3769 nodeBounds = getPathBounds(tree, lead);
3770 if(nodeBounds != null && visRect.intersects(nodeBounds))
3771 tree.repaint(0, nodeBounds.y, nWidth, nodeBounds.height);
3772 }
3773 }
3774
3775
3776
3777
3778
3779 public void treeExpanded(TreeExpansionEvent event) {
3780 if(event != null && tree != null) {
3781 TreePath path = event.getPath();
3782
3783 updateExpandedDescendants(path);
3784 }
3785 }
3786
3787 public void treeCollapsed(TreeExpansionEvent event) {
3788 if(event != null && tree != null) {
3789 TreePath path = event.getPath();
3790
3791 completeEditing();
3792 if(path != null && tree.isVisible(path)) {
3793 treeState.setExpandedState(path, false);
3794 updateLeadSelectionRow();
3795 updateSize();
3796 }
3797 }
3798 }
3799
3800
3801
3802
3803 public void treeNodesChanged(TreeModelEvent e) {
3804 if(treeState != null && e != null) {
3805 TreePath parentPath = e.getTreePath();
3806 int[] indices = e.getChildIndices();
3807 if (indices == null || indices.length == 0) {
3808
3809 treeState.treeNodesChanged(e);
3810 updateSize();
3811 }
3812 else if (treeState.isExpanded(parentPath)) {
3813
3814
3815
3816 int minIndex = indices[0];
3817 for (int i = indices.length - 1; i > 0; i--) {
3818 minIndex = Math.min(indices[i], minIndex);
3819 }
3820 Object minChild = treeModel.getChild(
3821 parentPath.getLastPathComponent(), minIndex);
3822 TreePath minPath = parentPath.pathByAddingChild(minChild);
3823 Rectangle minBounds = getPathBounds(tree, minPath);
3824
3825
3826 treeState.treeNodesChanged(e);
3827
3828
3829 updateSize0();
3830
3831
3832 Rectangle newMinBounds = getPathBounds(tree, minPath);
3833 if (indices.length == 1 &&
3834 newMinBounds.height == minBounds.height) {
3835 tree.repaint(0, minBounds.y, tree.getWidth(),
3836 minBounds.height);
3837 }
3838 else {
3839 tree.repaint(0, minBounds.y, tree.getWidth(),
3840 tree.getHeight() - minBounds.y);
3841 }
3842 }
3843 else {
3844
3845 treeState.treeNodesChanged(e);
3846 }
3847 }
3848 }
3849
3850 public void treeNodesInserted(TreeModelEvent e) {
3851 if(treeState != null && e != null) {
3852 treeState.treeNodesInserted(e);
3853
3854 updateLeadSelectionRow();
3855
3856 TreePath path = e.getTreePath();
3857
3858 if(treeState.isExpanded(path)) {
3859 updateSize();
3860 }
3861 else {
3862
3863
3864
3865 int[] indices = e.getChildIndices();
3866 int childCount = treeModel.getChildCount
3867 (path.getLastPathComponent());
3868
3869 if(indices != null && (childCount - indices.length) == 0)
3870 updateSize();
3871 }
3872 }
3873 }
3874
3875 public void treeNodesRemoved(TreeModelEvent e) {
3876 if(treeState != null && e != null) {
3877 treeState.treeNodesRemoved(e);
3878
3879 updateLeadSelectionRow();
3880
3881 TreePath path = e.getTreePath();
3882
3883 if(treeState.isExpanded(path) ||
3884 treeModel.getChildCount(path.getLastPathComponent()) == 0)
3885 updateSize();
3886 }
3887 }
3888
3889 public void treeStructureChanged(TreeModelEvent e) {
3890 if(treeState != null && e != null) {
3891 treeState.treeStructureChanged(e);
3892
3893 updateLeadSelectionRow();
3894
3895 TreePath pPath = e.getTreePath();
3896
3897 if (pPath != null) {
3898 pPath = pPath.getParentPath();
3899 }
3900 if(pPath == null || treeState.isExpanded(pPath))
3901 updateSize();
3902 }
3903 }
3904 }
3905
3906
3907
3908 private static class Actions extends UIAction {
3909 private static final String SELECT_PREVIOUS = "selectPrevious";
3910 private static final String SELECT_PREVIOUS_CHANGE_LEAD =
3911 "selectPreviousChangeLead";
3912 private static final String SELECT_PREVIOUS_EXTEND_SELECTION =
3913 "selectPreviousExtendSelection";
3914 private static final String SELECT_NEXT = "selectNext";
3915 private static final String SELECT_NEXT_CHANGE_LEAD =
3916 "selectNextChangeLead";
3917 private static final String SELECT_NEXT_EXTEND_SELECTION =
3918 "selectNextExtendSelection";
3919 private static final String SELECT_CHILD = "selectChild";
3920 private static final String SELECT_CHILD_CHANGE_LEAD =
3921 "selectChildChangeLead";
3922 private static final String SELECT_PARENT = "selectParent";
3923 private static final String SELECT_PARENT_CHANGE_LEAD =
3924 "selectParentChangeLead";
3925 private static final String SCROLL_UP_CHANGE_SELECTION =
3926 "scrollUpChangeSelection";
3927 private static final String SCROLL_UP_CHANGE_LEAD =
3928 "scrollUpChangeLead";
3929 private static final String SCROLL_UP_EXTEND_SELECTION =
3930 "scrollUpExtendSelection";
3931 private static final String SCROLL_DOWN_CHANGE_SELECTION =
3932 "scrollDownChangeSelection";
3933 private static final String SCROLL_DOWN_EXTEND_SELECTION =
3934 "scrollDownExtendSelection";
3935 private static final String SCROLL_DOWN_CHANGE_LEAD =
3936 "scrollDownChangeLead";
3937 private static final String SELECT_FIRST = "selectFirst";
3938 private static final String SELECT_FIRST_CHANGE_LEAD =
3939 "selectFirstChangeLead";
3940 private static final String SELECT_FIRST_EXTEND_SELECTION =
3941 "selectFirstExtendSelection";
3942 private static final String SELECT_LAST = "selectLast";
3943 private static final String SELECT_LAST_CHANGE_LEAD =
3944 "selectLastChangeLead";
3945 private static final String SELECT_LAST_EXTEND_SELECTION =
3946 "selectLastExtendSelection";
3947 private static final String TOGGLE = "toggle";
3948 private static final String CANCEL_EDITING = "cancel";
3949 private static final String START_EDITING = "startEditing";
3950 private static final String SELECT_ALL = "selectAll";
3951 private static final String CLEAR_SELECTION = "clearSelection";
3952 private static final String SCROLL_LEFT = "scrollLeft";
3953 private static final String SCROLL_RIGHT = "scrollRight";
3954 private static final String SCROLL_LEFT_EXTEND_SELECTION =
3955 "scrollLeftExtendSelection";
3956 private static final String SCROLL_RIGHT_EXTEND_SELECTION =
3957 "scrollRightExtendSelection";
3958 private static final String SCROLL_RIGHT_CHANGE_LEAD =
3959 "scrollRightChangeLead";
3960 private static final String SCROLL_LEFT_CHANGE_LEAD =
3961 "scrollLeftChangeLead";
3962 private static final String EXPAND = "expand";
3963 private static final String COLLAPSE = "collapse";
3964 private static final String MOVE_SELECTION_TO_PARENT =
3965 "moveSelectionToParent";
3966
3967
3968 private static final String ADD_TO_SELECTION = "addToSelection";
3969
3970
3971 private static final String TOGGLE_AND_ANCHOR = "toggleAndAnchor";
3972
3973
3974 private static final String EXTEND_TO = "extendTo";
3975
3976
3977 private static final String MOVE_SELECTION_TO = "moveSelectionTo";
3978
3979 Actions() {
3980 super(null);
3981 }
3982
3983 Actions(String key) {
3984 super(key);
3985 }
3986
3987 public boolean isEnabled(Object o) {
3988 if (o instanceof JTree) {
3989 if (getName() == CANCEL_EDITING) {
3990 return ((JTree)o).isEditing();
3991 }
3992 }
3993 return true;
3994 }
3995
3996 public void actionPerformed(ActionEvent e) {
3997 JTree tree = (JTree)e.getSource();
3998 BasicTreeUI ui = (BasicTreeUI)BasicLookAndFeel.getUIOfType(
3999 tree.getUI(), BasicTreeUI.class);
4000 if (ui == null) {
4001 return;
4002 }
4003 String key = getName();
4004 if (key == SELECT_PREVIOUS) {
4005 increment(tree, ui, -1, false, true);
4006 }
4007 else if (key == SELECT_PREVIOUS_CHANGE_LEAD) {
4008 increment(tree, ui, -1, false, false);
4009 }
4010 else if (key == SELECT_PREVIOUS_EXTEND_SELECTION) {
4011 increment(tree, ui, -1, true, true);
4012 }
4013 else if (key == SELECT_NEXT) {
4014 increment(tree, ui, 1, false, true);
4015 }
4016 else if (key == SELECT_NEXT_CHANGE_LEAD) {
4017 increment(tree, ui, 1, false, false);
4018 }
4019 else if (key == SELECT_NEXT_EXTEND_SELECTION) {
4020 increment(tree, ui, 1, true, true);
4021 }
4022 else if (key == SELECT_CHILD) {
4023 traverse(tree, ui, 1, true);
4024 }
4025 else if (key == SELECT_CHILD_CHANGE_LEAD) {
4026 traverse(tree, ui, 1, false);
4027 }
4028 else if (key == SELECT_PARENT) {
4029 traverse(tree, ui, -1, true);
4030 }
4031 else if (key == SELECT_PARENT_CHANGE_LEAD) {
4032 traverse(tree, ui, -1, false);
4033 }
4034 else if (key == SCROLL_UP_CHANGE_SELECTION) {
4035 page(tree, ui, -1, false, true);
4036 }
4037 else if (key == SCROLL_UP_CHANGE_LEAD) {
4038 page(tree, ui, -1, false, false);
4039 }
4040 else if (key == SCROLL_UP_EXTEND_SELECTION) {
4041 page(tree, ui, -1, true, true);
4042 }
4043 else if (key == SCROLL_DOWN_CHANGE_SELECTION) {
4044 page(tree, ui, 1, false, true);
4045 }
4046 else if (key == SCROLL_DOWN_EXTEND_SELECTION) {
4047 page(tree, ui, 1, true, true);
4048 }
4049 else if (key == SCROLL_DOWN_CHANGE_LEAD) {
4050 page(tree, ui, 1, false, false);
4051 }
4052 else if (key == SELECT_FIRST) {
4053 home(tree, ui, -1, false, true);
4054 }
4055 else if (key == SELECT_FIRST_CHANGE_LEAD) {
4056 home(tree, ui, -1, false, false);
4057 }
4058 else if (key == SELECT_FIRST_EXTEND_SELECTION) {
4059 home(tree, ui, -1, true, true);
4060 }
4061 else if (key == SELECT_LAST) {
4062 home(tree, ui, 1, false, true);
4063 }
4064 else if (key == SELECT_LAST_CHANGE_LEAD) {
4065 home(tree, ui, 1, false, false);
4066 }
4067 else if (key == SELECT_LAST_EXTEND_SELECTION) {
4068 home(tree, ui, 1, true, true);
4069 }
4070 else if (key == TOGGLE) {
4071 toggle(tree, ui);
4072 }
4073 else if (key == CANCEL_EDITING) {
4074 cancelEditing(tree, ui);
4075 }
4076 else if (key == START_EDITING) {
4077 startEditing(tree, ui);
4078 }
4079 else if (key == SELECT_ALL) {
4080 selectAll(tree, ui, true);
4081 }
4082 else if (key == CLEAR_SELECTION) {
4083 selectAll(tree, ui, false);
4084 }
4085 else if (key == ADD_TO_SELECTION) {
4086 if (ui.getRowCount(tree) > 0) {
4087 int lead = ui.getLeadSelectionRow();
4088 if (!tree.isRowSelected(lead)) {
4089 TreePath aPath = ui.getAnchorSelectionPath();
4090 tree.addSelectionRow(lead);
4091 ui.setAnchorSelectionPath(aPath);
4092 }
4093 }
4094 }
4095 else if (key == TOGGLE_AND_ANCHOR) {
4096 if (ui.getRowCount(tree) > 0) {
4097 int lead = ui.getLeadSelectionRow();
4098 TreePath lPath = ui.getLeadSelectionPath();
4099 if (!tree.isRowSelected(lead)) {
4100 tree.addSelectionRow(lead);
4101 } else {
4102 tree.removeSelectionRow(lead);
4103 ui.setLeadSelectionPath(lPath);
4104 }
4105 ui.setAnchorSelectionPath(lPath);
4106 }
4107 }
4108 else if (key == EXTEND_TO) {
4109 extendSelection(tree, ui);
4110 }
4111 else if (key == MOVE_SELECTION_TO) {
4112 if (ui.getRowCount(tree) > 0) {
4113 int lead = ui.getLeadSelectionRow();
4114 tree.setSelectionInterval(lead, lead);
4115 }
4116 }
4117 else if (key == SCROLL_LEFT) {
4118 scroll(tree, ui, SwingConstants.HORIZONTAL, -10);
4119 }
4120 else if (key == SCROLL_RIGHT) {
4121 scroll(tree, ui, SwingConstants.HORIZONTAL, 10);
4122 }
4123 else if (key == SCROLL_LEFT_EXTEND_SELECTION) {
4124 scrollChangeSelection(tree, ui, -1, true, true);
4125 }
4126 else if (key == SCROLL_RIGHT_EXTEND_SELECTION) {
4127 scrollChangeSelection(tree, ui, 1, true, true);
4128 }
4129 else if (key == SCROLL_RIGHT_CHANGE_LEAD) {
4130 scrollChangeSelection(tree, ui, 1, false, false);
4131 }
4132 else if (key == SCROLL_LEFT_CHANGE_LEAD) {
4133 scrollChangeSelection(tree, ui, -1, false, false);
4134 }
4135 else if (key == EXPAND) {
4136 expand(tree, ui);
4137 }
4138 else if (key == COLLAPSE) {
4139 collapse(tree, ui);
4140 }
4141 else if (key == MOVE_SELECTION_TO_PARENT) {
4142 moveSelectionToParent(tree, ui);
4143 }
4144 }
4145
4146 private void scrollChangeSelection(JTree tree, BasicTreeUI ui,
4147 int direction, boolean addToSelection,
4148 boolean changeSelection) {
4149 int rowCount;
4150
4151 if((rowCount = ui.getRowCount(tree)) > 0 &&
4152 ui.treeSelectionModel != null) {
4153 TreePath newPath;
4154 Rectangle visRect = tree.getVisibleRect();
4155
4156 if (direction == -1) {
4157 newPath = ui.getClosestPathForLocation(tree, visRect.x,
4158 visRect.y);
4159 visRect.x = Math.max(0, visRect.x - visRect.width);
4160 }
4161 else {
4162 visRect.x = Math.min(Math.max(0, tree.getWidth() -
4163 visRect.width), visRect.x + visRect.width);
4164 newPath = ui.getClosestPathForLocation(tree, visRect.x,
4165 visRect.y + visRect.height);
4166 }
4167
4168 tree.scrollRectToVisible(visRect);
4169
4170 if (addToSelection) {
4171 ui.extendSelection(newPath);
4172 }
4173 else if(changeSelection) {
4174 tree.setSelectionPath(newPath);
4175 }
4176 else {
4177 ui.setLeadSelectionPath(newPath, true);
4178 }
4179 }
4180 }
4181
4182 private void scroll(JTree component, BasicTreeUI ui, int direction,
4183 int amount) {
4184 Rectangle visRect = component.getVisibleRect();
4185 Dimension size = component.getSize();
4186 if (direction == SwingConstants.HORIZONTAL) {
4187 visRect.x += amount;
4188 visRect.x = Math.max(0, visRect.x);
4189 visRect.x = Math.min(Math.max(0, size.width - visRect.width),
4190 visRect.x);
4191 }
4192 else {
4193 visRect.y += amount;
4194 visRect.y = Math.max(0, visRect.y);
4195 visRect.y = Math.min(Math.max(0, size.width - visRect.height),
4196 visRect.y);
4197 }
4198 component.scrollRectToVisible(visRect);
4199 }
4200
4201 private void extendSelection(JTree tree, BasicTreeUI ui) {
4202 if (ui.getRowCount(tree) > 0) {
4203 int lead = ui.getLeadSelectionRow();
4204
4205 if (lead != -1) {
4206 TreePath leadP = ui.getLeadSelectionPath();
4207 TreePath aPath = ui.getAnchorSelectionPath();
4208 int aRow = ui.getRowForPath(tree, aPath);
4209
4210 if(aRow == -1)
4211 aRow = 0;
4212 tree.setSelectionInterval(aRow, lead);
4213 ui.setLeadSelectionPath(leadP);
4214 ui.setAnchorSelectionPath(aPath);
4215 }
4216 }
4217 }
4218
4219 private void selectAll(JTree tree, BasicTreeUI ui, boolean selectAll) {
4220 int rowCount = ui.getRowCount(tree);
4221
4222 if(rowCount > 0) {
4223 if(selectAll) {
4224 if (tree.getSelectionModel().getSelectionMode() ==
4225 TreeSelectionModel.SINGLE_TREE_SELECTION) {
4226
4227 int lead = ui.getLeadSelectionRow();
4228 if (lead != -1) {
4229 tree.setSelectionRow(lead);
4230 } else if (tree.getMinSelectionRow() == -1) {
4231 tree.setSelectionRow(0);
4232 ui.ensureRowsAreVisible(0, 0);
4233 }
4234 return;
4235 }
4236
4237 TreePath lastPath = ui.getLeadSelectionPath();
4238 TreePath aPath = ui.getAnchorSelectionPath();
4239
4240 if(lastPath != null && !tree.isVisible(lastPath)) {
4241 lastPath = null;
4242 }
4243 tree.setSelectionInterval(0, rowCount - 1);
4244 if(lastPath != null) {
4245 ui.setLeadSelectionPath(lastPath);
4246 }
4247 if(aPath != null && tree.isVisible(aPath)) {
4248 ui.setAnchorSelectionPath(aPath);
4249 }
4250 }
4251 else {
4252 TreePath lastPath = ui.getLeadSelectionPath();
4253 TreePath aPath = ui.getAnchorSelectionPath();
4254
4255 tree.clearSelection();
4256 ui.setAnchorSelectionPath(aPath);
4257 ui.setLeadSelectionPath(lastPath);
4258 }
4259 }
4260 }
4261
4262 private void startEditing(JTree tree, BasicTreeUI ui) {
4263 TreePath lead = ui.getLeadSelectionPath();
4264 int editRow = (lead != null) ?
4265 ui.getRowForPath(tree, lead) : -1;
4266
4267 if(editRow != -1) {
4268 tree.startEditingAtPath(lead);
4269 }
4270 }
4271
4272 private void cancelEditing(JTree tree, BasicTreeUI ui) {
4273 tree.cancelEditing();
4274 }
4275
4276 private void toggle(JTree tree, BasicTreeUI ui) {
4277 int selRow = ui.getLeadSelectionRow();
4278
4279 if(selRow != -1 && !ui.isLeaf(selRow)) {
4280 TreePath aPath = ui.getAnchorSelectionPath();
4281 TreePath lPath = ui.getLeadSelectionPath();
4282
4283 ui.toggleExpandState(ui.getPathForRow(tree, selRow));
4284 ui.setAnchorSelectionPath(aPath);
4285 ui.setLeadSelectionPath(lPath);
4286 }
4287 }
4288
4289 private void expand(JTree tree, BasicTreeUI ui) {
4290 int selRow = ui.getLeadSelectionRow();
4291 tree.expandRow(selRow);
4292 }
4293
4294 private void collapse(JTree tree, BasicTreeUI ui) {
4295 int selRow = ui.getLeadSelectionRow();
4296 tree.collapseRow(selRow);
4297 }
4298
4299 private void increment(JTree tree, BasicTreeUI ui, int direction,
4300 boolean addToSelection,
4301 boolean changeSelection) {
4302
4303
4304 if (!addToSelection && !changeSelection &&
4305 tree.getSelectionModel().getSelectionMode() !=
4306 TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION) {
4307 changeSelection = true;
4308 }
4309
4310 int rowCount;
4311
4312 if(ui.treeSelectionModel != null &&
4313 (rowCount = tree.getRowCount()) > 0) {
4314 int selIndex = ui.getLeadSelectionRow();
4315 int newIndex;
4316
4317 if(selIndex == -1) {
4318 if(direction == 1)
4319 newIndex = 0;
4320 else
4321 newIndex = rowCount - 1;
4322 }
4323 else
4324
4325 newIndex = Math.min(rowCount - 1, Math.max
4326 (0, (selIndex + direction)));
4327 if(addToSelection && ui.treeSelectionModel.
4328 getSelectionMode() != TreeSelectionModel.
4329 SINGLE_TREE_SELECTION) {
4330 ui.extendSelection(tree.getPathForRow(newIndex));
4331 }
4332 else if(changeSelection) {
4333 tree.setSelectionInterval(newIndex, newIndex);
4334 }
4335 else {
4336 ui.setLeadSelectionPath(tree.getPathForRow(newIndex),true);
4337 }
4338 ui.ensureRowsAreVisible(newIndex, newIndex);
4339 ui.lastSelectedRow = newIndex;
4340 }
4341 }
4342
4343 private void traverse(JTree tree, BasicTreeUI ui, int direction,
4344 boolean changeSelection) {
4345
4346
4347 if (!changeSelection &&
4348 tree.getSelectionModel().getSelectionMode() !=
4349 TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION) {
4350 changeSelection = true;
4351 }
4352
4353 int rowCount;
4354
4355 if((rowCount = tree.getRowCount()) > 0) {
4356 int minSelIndex = ui.getLeadSelectionRow();
4357 int newIndex;
4358
4359 if(minSelIndex == -1)
4360 newIndex = 0;
4361 else {
4362
4363
4364 if(direction == 1) {
4365 TreePath minSelPath = ui.getPathForRow(tree, minSelIndex);
4366 int childCount = tree.getModel().
4367 getChildCount(minSelPath.getLastPathComponent());
4368 newIndex = -1;
4369 if (!ui.isLeaf(minSelIndex)) {
4370 if (!tree.isExpanded(minSelIndex)) {
4371 ui.toggleExpandState(minSelPath);
4372 }
4373 else if (childCount > 0) {
4374 newIndex = Math.min(minSelIndex + 1, rowCount - 1);
4375 }
4376 }
4377 }
4378
4379 else {
4380 if(!ui.isLeaf(minSelIndex) &&
4381 tree.isExpanded(minSelIndex)) {
4382 ui.toggleExpandState(ui.getPathForRow
4383 (tree, minSelIndex));
4384 newIndex = -1;
4385 }
4386 else {
4387 TreePath path = ui.getPathForRow(tree,
4388 minSelIndex);
4389
4390 if(path != null && path.getPathCount() > 1) {
4391 newIndex = ui.getRowForPath(tree, path.
4392 getParentPath());
4393 }
4394 else
4395 newIndex = -1;
4396 }
4397 }
4398 }
4399 if(newIndex != -1) {
4400 if(changeSelection) {
4401 tree.setSelectionInterval(newIndex, newIndex);
4402 }
4403 else {
4404 ui.setLeadSelectionPath(ui.getPathForRow(
4405 tree, newIndex), true);
4406 }
4407 ui.ensureRowsAreVisible(newIndex, newIndex);
4408 }
4409 }
4410 }
4411
4412 private void moveSelectionToParent(JTree tree, BasicTreeUI ui) {
4413 int selRow = ui.getLeadSelectionRow();
4414 TreePath path = ui.getPathForRow(tree, selRow);
4415 if (path != null && path.getPathCount() > 1) {
4416 int newIndex = ui.getRowForPath(tree, path.getParentPath());
4417 if (newIndex != -1) {
4418 tree.setSelectionInterval(newIndex, newIndex);
4419 ui.ensureRowsAreVisible(newIndex, newIndex);
4420 }
4421 }
4422 }
4423
4424 private void page(JTree tree, BasicTreeUI ui, int direction,
4425 boolean addToSelection, boolean changeSelection) {
4426
4427
4428 if (!addToSelection && !changeSelection &&
4429 tree.getSelectionModel().getSelectionMode() !=
4430 TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION) {
4431 changeSelection = true;
4432 }
4433
4434 int rowCount;
4435
4436 if((rowCount = ui.getRowCount(tree)) > 0 &&
4437 ui.treeSelectionModel != null) {
4438 Dimension maxSize = tree.getSize();
4439 TreePath lead = ui.getLeadSelectionPath();
4440 TreePath newPath;
4441 Rectangle visRect = tree.getVisibleRect();
4442
4443 if(direction == -1) {
4444
4445 newPath = ui.getClosestPathForLocation(tree, visRect.x,
4446 visRect.y);
4447 if(newPath.equals(lead)) {
4448 visRect.y = Math.max(0, visRect.y - visRect.height);
4449 newPath = tree.getClosestPathForLocation(visRect.x,
4450 visRect.y);
4451 }
4452 }
4453 else {
4454
4455 visRect.y = Math.min(maxSize.height, visRect.y +
4456 visRect.height - 1);
4457 newPath = tree.getClosestPathForLocation(visRect.x,
4458 visRect.y);
4459 if(newPath.equals(lead)) {
4460 visRect.y = Math.min(maxSize.height, visRect.y +
4461 visRect.height - 1);
4462 newPath = tree.getClosestPathForLocation(visRect.x,
4463 visRect.y);
4464 }
4465 }
4466 Rectangle newRect = ui.getPathBounds(tree, newPath);
4467
4468 newRect.x = visRect.x;
4469 newRect.width = visRect.width;
4470 if(direction == -1) {
4471 newRect.height = visRect.height;
4472 }
4473 else {
4474 newRect.y -= (visRect.height - newRect.height);
4475 newRect.height = visRect.height;
4476 }
4477
4478 if(addToSelection) {
4479 ui.extendSelection(newPath);
4480 }
4481 else if(changeSelection) {
4482 tree.setSelectionPath(newPath);
4483 }
4484 else {
4485 ui.setLeadSelectionPath(newPath, true);
4486 }
4487 tree.scrollRectToVisible(newRect);
4488 }
4489 }
4490
4491 private void home(JTree tree, BasicTreeUI ui, int direction,
4492 boolean addToSelection, boolean changeSelection) {
4493
4494
4495 if (!addToSelection && !changeSelection &&
4496 tree.getSelectionModel().getSelectionMode() !=
4497 TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION) {
4498 changeSelection = true;
4499 }
4500
4501 int rowCount = ui.getRowCount(tree);
4502
4503 if (rowCount > 0) {
4504 if(direction == -1) {
4505 ui.ensureRowsAreVisible(0, 0);
4506 if (addToSelection) {
4507 TreePath aPath = ui.getAnchorSelectionPath();
4508 int aRow = (aPath == null) ? -1 :
4509 ui.getRowForPath(tree, aPath);
4510
4511 if (aRow == -1) {
4512 tree.setSelectionInterval(0, 0);
4513 }
4514 else {
4515 tree.setSelectionInterval(0, aRow);
4516 ui.setAnchorSelectionPath(aPath);
4517 ui.setLeadSelectionPath(ui.getPathForRow(tree, 0));
4518 }
4519 }
4520 else if(changeSelection) {
4521 tree.setSelectionInterval(0, 0);
4522 }
4523 else {
4524 ui.setLeadSelectionPath(ui.getPathForRow(tree, 0),
4525 true);
4526 }
4527 }
4528 else {
4529 ui.ensureRowsAreVisible(rowCount - 1, rowCount - 1);
4530 if (addToSelection) {
4531 TreePath aPath = ui.getAnchorSelectionPath();
4532 int aRow = (aPath == null) ? -1 :
4533 ui.getRowForPath(tree, aPath);
4534
4535 if (aRow == -1) {
4536 tree.setSelectionInterval(rowCount - 1,
4537 rowCount -1);
4538 }
4539 else {
4540 tree.setSelectionInterval(aRow, rowCount - 1);
4541 ui.setAnchorSelectionPath(aPath);
4542 ui.setLeadSelectionPath(ui.getPathForRow(tree,
4543 rowCount -1));
4544 }
4545 }
4546 else if(changeSelection) {
4547 tree.setSelectionInterval(rowCount - 1, rowCount - 1);
4548 }
4549 else {
4550 ui.setLeadSelectionPath(ui.getPathForRow(tree,
4551 rowCount - 1), true);
4552 }
4553 }
4554 }
4555 }
4556 }
4557 }